diff options
413 files changed, 12573 insertions, 8197 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cd4c03372b..ed8067f5cf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,7 +59,7 @@ build-user: build-clang: script: - - apt-get install -y -qq clang libsdl2-dev + - apt-get install -y -qq clang libsdl2-dev libattr1-dev libcap-dev xfslibs-dev libiscsi-dev libnfs-dev libseccomp-dev gnutls-dev librbd-dev - ./configure --cc=clang --cxx=clang++ --enable-werror --target-list="alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu @@ -1,23 +1,29 @@ # This mailmap fixes up author names/addresses. +# +# If you are adding to this file consider if a similar change needs to +# be made to contrib/gitdm/aliases. They are not however completely +# analogous. .mailmap is concerned with fixing up damaged author +# fields where as the gitdm equivalent is more concerned with making +# sure multiple email addresses get mapped onto the same author. +# +# From man git-shortlog the forms are: +# +# Proper Name <commit@email.xx> +# <proper@email.xx> <commit@email.xx> +# Proper Name <proper@email.xx> <commit@email.xx> +# Proper Name <proper@email.xx> Commit Name <commit@email.xx> +# # The first section translates weird addresses from the original git import # into proper addresses so that they are counted properly by git shortlog. Andrzej Zaborowski <balrogg@gmail.com> balrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162> Anthony Liguori <anthony@codemonkey.ws> aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162> -Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com> Aurelien Jarno <aurelien@aurel32.net> aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162> Blue Swirl <blauwirbel@gmail.com> blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162> Edgar E. Iglesias <edgar.iglesias@gmail.com> edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162> Fabrice Bellard <fabrice@bellard.org> bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> -James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com> Jocelyn Mayer <l_indien@magic.fr> j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162> Paul Brook <paul@codesourcery.com> pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> -Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com> -Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@mips.com> -Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@imgtec.com> -Paul Burton <pburton@wavecomp.com> <paul.burton@mips.com> -Paul Burton <pburton@wavecomp.com> <paul.burton@imgtec.com> -Paul Burton <pburton@wavecomp.com> <paul@archlinuxmips.org> Thiemo Seufer <ths@networkno.de> ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> malc <av1474@comtv.ru> malc <malc@c046a42c-6fe2-441c-8c8c-71466251a162> @@ -32,8 +38,123 @@ Ian McKellar <ianloic@google.com> Ian McKellar via Qemu-devel <qemu-devel@nongnu Julia Suvorova <jusual@mail.ru> Julia Suvorova via Qemu-devel <qemu-devel@nongnu.org> Justin Terry (VM) <juterry@microsoft.com> Justin Terry (VM) via Qemu-devel <qemu-devel@nongnu.org> +# Next, replace old addresses by a more recent one. +Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com> +James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com> +Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@mips.com> +Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@imgtec.com> +Paul Burton <pburton@wavecomp.com> <paul.burton@mips.com> +Paul Burton <pburton@wavecomp.com> <paul.burton@imgtec.com> +Paul Burton <pburton@wavecomp.com> <paul@archlinuxmips.org> +Philippe Mathieu-Daudé <philmd@redhat.com> <f4bug@amsat.org> +Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com> # Also list preferred name forms where people have changed their # git author config, or had utf8/latin1 encoding issues. +Aaron Lindsay <aaron@os.amperecomputing.com> +Alexey Gerasimenko <x1917x@gmail.com> +Alex Ivanov <void@aleksoft.net> +Andreas Färber <afaerber@suse.de> +Bandan Das <bsd@redhat.com> +Benjamin MARSILI <mlspirat42@gmail.com> +Benoît Canet <benoit.canet@gmail.com> +Benoît Canet <benoit.canet@irqsave.net> +Benoît Canet <benoit.canet@nodalink.com> +Boqun Feng <boqun.feng@gmail.com> +Boqun Feng <boqun.feng@intel.com> +Brad Smith <brad@comstyle.com> +Brijesh Singh <brijesh.singh@amd.com> +Brilly Wu <brillywu@viatech.com.cn> +Cédric Vincent <cedric.vincent@st.com> +CheneyLin <linzc@zju.edu.cn> +Chen Gang <chengang@emindsoft.com.cn> +Chen Gang <gang.chen.5i5j@gmail.com> +Chen Gang <gang.chen@sunrus.com.cn> +Chen Wei-Ren <chenwj@iis.sinica.edu.tw> +Christophe Lyon <christophe.lyon@st.com> +Collin L. Walling <walling@linux.ibm.com> Daniel P. Berrangé <berrange@redhat.com> +Eduardo Otubo <otubo@redhat.com> +Fabrice Desclaux <fabrice.desclaux@cea.fr> +Fernando Luis Vázquez Cao <fernando_b1@lab.ntt.co.jp> +Fernando Luis Vázquez Cao <fernando@oss.ntt.co.jp> +Gautham R. Shenoy <ego@in.ibm.com> +Gautham R. Shenoy <ego@linux.vnet.ibm.com> +Gonglei (Arei) <arei.gonglei@huawei.com> +Guang Wang <wang.guang55@zte.com.cn> +Hailiang Zhang <zhang.zhanghailiang@huawei.com> +Hervé Poussineau <hpoussin@reactos.org> +Jakub Jermář <jakub@jermar.eu> +Jakub Jermář <jakub.jermar@kernkonzept.com> +Jean-Christophe Dubois <jcd@tribudubois.net> +Jindřich Makovička <makovick@gmail.com> +John Arbuckle <programmingkidx@gmail.com> +Juha Riihimäki <juha.riihimaki@nokia.com> +Juha Riihimäki <Juha.Riihimaki@nokia.com> +Jun Li <junmuzi@gmail.com> +Laurent Vivier <Laurent@lvivier.info> +Leandro Lupori <leandro.lupori@gmail.com> +Li Guang <lig.fnst@cn.fujitsu.com> +Liming Wang <walimisdev@gmail.com> +linzhecheng <linzc@zju.edu.cn> +Liran Schour <lirans@il.ibm.com> +Liu Yu <yu.liu@freescale.com> +Liu Yu <Yu.Liu@freescale.com> +Li Zhang <zhlcindy@gmail.com> +Li Zhang <zhlcindy@linux.vnet.ibm.com> +Lluís Vilanova <vilanova@ac.upc.edu> +Lluís Vilanova <xscript@gmx.net> +Longpeng (Mike) <longpeng2@huawei.com> +Luc Michel <luc.michel@git.antfield.fr> +Luc Michel <luc.michel@greensocs.com> +Marc Marí <marc.mari.barcelo@gmail.com> +Marc Marí <markmb@redhat.com> +Michael Avdienko <whitearchey@gmail.com> +Michael S. Tsirkin <mst@redhat.com> +Munkyu Im <munkyu.im@samsung.com> +Nicholas Bellinger <nab@linux-iscsi.org> +Nicholas Thomas <nick@bytemark.co.uk> +Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> +Orit Wasserman <owasserm@redhat.com> +Paolo Bonzini <pbonzini@redhat.com> +Pavel Dovgaluk <dovgaluk@ispras.ru> +Pavel Dovgaluk <pavel.dovgaluk@gmail.com> +Pavel Dovgaluk <Pavel.Dovgaluk@ispras.ru> +Peter Crosthwaite <crosthwaite.peter@gmail.com> +Peter Crosthwaite <peter.crosthwaite@petalogix.com> +Peter Crosthwaite <peter.crosthwaite@xilinx.com> +Prasad J Pandit <pjp@fedoraproject.org> +Prasad J Pandit <ppandit@redhat.com> +Qiao Nuohan <qiaonuohan@cn.fujitsu.com> Reimar Döffinger <Reimar.Doeffinger@gmx.de> +Remy Noel <remy.noel@blade-group.com> +Roger Pau Monné <roger.pau@citrix.com> +Shin'ichiro Kawasaki <kawasaki@juno.dti.ne.jp> +Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com> +Sochin Jiang <sochin.jiang@huawei.com> +Takashi Yoshii <takasi-y@ops.dti.ne.jp> +Thomas Huth <thuth@redhat.com> +Thomas Knych <thomaswk@google.com> +Timothy Baldwin <T.E.Baldwin99@members.leeds.ac.uk> +Tony Nguyen <tony.nguyen@bt.com> +Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com> +Vibi Sreenivasan <vibi_sreenivasan@cms.com> +Vijaya Kumar K <vijayak@cavium.com> +Vijaya Kumar K <Vijaya.Kumar@cavium.com> +Vijay Kumar <vijaykumar@bravegnu.org> +Vijay Kumar <vijaykumar@zilogic.com> +Wang Guang <wang.guang55@zte.com.cn> +Wenchao Xia <xiawenc@linux.vnet.ibm.com> +Wenshuang Ma <kevinnma@tencent.com> +Xiaoqiang Zhao <zxq_yx_007@163.com> +Xinhua Cao <caoxinhua@huawei.com> +Xiong Zhang <xiong.y.zhang@intel.com> +Yin Yin <yin.yin@cs2c.com.cn> +yuchenlin <npes87184@gmail.com> +YunQiang Su <syq@debian.org> +YunQiang Su <ysu@wavecomp.com> +Yuri Pudgorodskiy <yur@virtuozzo.com> +Zhengui Li <lizhengui@huawei.com> +Zhenwei Pi <pizhenwei@bytedance.com> +Zhenwei Pi <zhenwei.pi@youruncloud.com> +Zhuang Yanying <ann.zhuangyanying@huawei.com> diff --git a/.shippable.yml b/.shippable.yml index f74a3de3ff..bbc6f88510 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -27,6 +27,8 @@ env: TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user build: pre_ci: + # usually host ARCH is set by configure + - echo "ARCH=$(uname -m)" > config-host.mak - make docker-image-${IMAGE} V=1 pre_ci_boot: image_name: qemu diff --git a/.travis.yml b/.travis.yml index caf0a1f8fa..d0b9e099b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,18 @@ dist: xenial language: c compiler: - gcc -cache: ccache +cache: + # There is one cache per branch and compiler version. + # characteristics of each job are used to identify the cache: + # - OS name (currently, linux, osx, or windows) + # - OS distribution (for Linux, xenial, trusty, or precise) + # - macOS image name (e.g., xcode7.2) + # - Names and values of visible environment variables set in .travis.yml or Settings panel + timeout: 1200 + ccache: true + pip: true + directories: + - $HOME/avocado/data/cache addons: @@ -15,6 +26,7 @@ addons: - libaio-dev - libattr1-dev - libbrlapi-dev + - libcap-dev - libcap-ng-dev - libgcc-4.8-dev - libgnutls-dev @@ -40,6 +52,7 @@ addons: - gcovr homebrew: packages: + - ccache - glib - pixman - gnu-sed @@ -65,6 +78,9 @@ env: - TEST_CMD="make check -j3 V=1" # This is broadly a list of "mainline" softmmu targets which have support across the major distros - MAIN_SOFTMMU_TARGETS="aarch64-softmmu,arm-softmmu,i386-softmmu,mips-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu" + - CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime" + - CCACHE_MAXSIZE=1G + git: # we want to do this ourselves @@ -72,25 +88,32 @@ git: before_script: + - if [ "$TRAVIS_OS_NAME" == "osx" ] ; then export PATH="/usr/local/opt/ccache/libexec:$PATH" ; fi + - command -v ccache && ccache --zero-stats - mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR} - ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; } script: - make -j3 && travis_retry ${TEST_CMD} +after_script: + - command -v ccache && ccache --show-stats matrix: include: - env: - CONFIG="--disable-system --static" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" # we split the system builds as it takes a while to build them all - env: - CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" - env: - CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" # Just build tools and run minimal unit and softfloat checks @@ -98,14 +121,18 @@ matrix: - BASE_CONFIG="--enable-tools" - CONFIG="--disable-user --disable-system" - TEST_CMD="make check-unit check-softfloat -j3" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" + - env: - CONFIG="--enable-debug --enable-debug-tcg --disable-user" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug" # TCG debug can be run just on it's own and is mostly agnostic to user/softmmu distinctions - env: - CONFIG="--enable-debug-tcg --disable-system" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug" - env: @@ -115,6 +142,7 @@ matrix: # Module builds are mostly of interest to major distros - env: - CONFIG="--enable-modules --target-list=${MAIN_SOFTMMU_TARGETS}" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" # Alternate coroutines implementations are only really of interest to KVM users @@ -134,6 +162,7 @@ matrix: - BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.." - BASE_CONFIG="--enable-tools --enable-docs" - CONFIG="--target-list=x86_64-softmmu,aarch64-linux-user" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" addons: apt: packages: @@ -145,11 +174,13 @@ matrix: # Test with Clang for compile portability (Travis uses clang-5.0) - env: - CONFIG="--disable-system" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default" compiler: clang - env: - CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default" compiler: clang @@ -162,6 +193,7 @@ matrix: - env: - CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default" compiler: clang @@ -175,6 +207,7 @@ matrix: # We manually include builds which we disable "make check" for - env: - CONFIG="--without-default-devices --disable-user" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" - TEST_CMD="" @@ -218,6 +251,7 @@ matrix: # Python builds - env: - CONFIG="--target-list=x86_64-softmmu" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" language: python python: - "3.4" @@ -225,6 +259,7 @@ matrix: - env: - CONFIG="--target-list=x86_64-softmmu" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" language: python python: - "3.6" @@ -232,15 +267,20 @@ matrix: # Acceptance (Functional) tests - env: - - CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu" + - CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu,ppc64-softmmu,m68k-softmmu" - TEST_CMD="make check-acceptance" after_failure: - cat tests/results/latest/job.log addons: apt: packages: + - python3-pil - python3-pip - python3.5-venv + - tesseract-ocr + - tesseract-ocr-eng + + # Using newer GCC with sanitizers - addons: apt: @@ -291,8 +331,11 @@ matrix: - env: - CONFIG="--disable-system" - TEST_CMD="make -j3 check-tcg V=1" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" + # Run check-tcg against softmmu targets - env: - CONFIG="--target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu" - TEST_CMD="make -j3 check-tcg V=1" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default" diff --git a/CODING_STYLE b/CODING_STYLE deleted file mode 100644 index cb8edcbb36..0000000000 --- a/CODING_STYLE +++ /dev/null @@ -1,216 +0,0 @@ -QEMU Coding Style -================= - -Please use the script checkpatch.pl in the scripts directory to check -patches before submitting. - -1. Whitespace - -Of course, the most important aspect in any coding style is whitespace. -Crusty old coders who have trouble spotting the glasses on their noses -can tell the difference between a tab and eight spaces from a distance -of approximately fifteen parsecs. Many a flamewar has been fought and -lost on this issue. - -QEMU indents are four spaces. Tabs are never used, except in Makefiles -where they have been irreversibly coded into the syntax. -Spaces of course are superior to tabs because: - - - You have just one way to specify whitespace, not two. Ambiguity breeds - mistakes. - - The confusion surrounding 'use tabs to indent, spaces to justify' is gone. - - Tab indents push your code to the right, making your screen seriously - unbalanced. - - Tabs will be rendered incorrectly on editors who are misconfigured not - to use tab stops of eight positions. - - Tabs are rendered badly in patches, causing off-by-one errors in almost - every line. - - It is the QEMU coding style. - -Do not leave whitespace dangling off the ends of lines. - -1.1 Multiline Indent - -There are several places where indent is necessary: - - - if/else - - while/for - - function definition & call - -When breaking up a long line to fit within line width, we need a proper indent -for the following lines. - -In case of if/else, while/for, align the secondary lines just after the -opening parenthesis of the first. - -For example: - - if (a == 1 && - b == 2) { - - while (a == 1 && - b == 2) { - -In case of function, there are several variants: - - * 4 spaces indent from the beginning - * align the secondary lines just after the opening parenthesis of the - first - -For example: - - do_something(x, y, - z); - - do_something(x, y, - z); - - do_something(x, do_another(y, - z)); - -2. Line width - -Lines should be 80 characters; try not to make them longer. - -Sometimes it is hard to do, especially when dealing with QEMU subsystems -that use long function or symbol names. Even in that case, do not make -lines much longer than 80 characters. - -Rationale: - - Some people like to tile their 24" screens with a 6x4 matrix of 80x24 - xterms and use vi in all of them. The best way to punish them is to - let them keep doing it. - - Code and especially patches is much more readable if limited to a sane - line length. Eighty is traditional. - - The four-space indentation makes the most common excuse ("But look - at all that white space on the left!") moot. - - It is the QEMU coding style. - -3. Naming - -Variables are lower_case_with_underscores; easy to type and read. Structured -type names are in CamelCase; harder to type but standing out. Enum type -names and function type names should also be in CamelCase. Scalar type -names are lower_case_with_underscores_ending_with_a_t, like the POSIX -uint64_t and family. Note that this last convention contradicts POSIX -and is therefore likely to be changed. - -When wrapping standard library functions, use the prefix qemu_ to alert -readers that they are seeing a wrapped version; otherwise avoid this prefix. - -4. Block structure - -Every indented statement is braced; even if the block contains just one -statement. The opening brace is on the line that contains the control -flow statement that introduces the new block; the closing brace is on the -same line as the else keyword, or on a line by itself if there is no else -keyword. Example: - - if (a == 5) { - printf("a was 5.\n"); - } else if (a == 6) { - printf("a was 6.\n"); - } else { - printf("a was something else entirely.\n"); - } - -Note that 'else if' is considered a single statement; otherwise a long if/ -else if/else if/.../else sequence would need an indent for every else -statement. - -An exception is the opening brace for a function; for reasons of tradition -and clarity it comes on a line by itself: - - void a_function(void) - { - do_something(); - } - -Rationale: a consistent (except for functions...) bracing style reduces -ambiguity and avoids needless churn when lines are added or removed. -Furthermore, it is the QEMU coding style. - -5. Declarations - -Mixed declarations (interleaving statements and declarations within -blocks) are generally not allowed; declarations should be at the beginning -of blocks. - -Every now and then, an exception is made for declarations inside a -#ifdef or #ifndef block: if the code looks nicer, such declarations can -be placed at the top of the block even if there are statements above. -On the other hand, however, it's often best to move that #ifdef/#ifndef -block to a separate function altogether. - -6. Conditional statements - -When comparing a variable for (in)equality with a constant, list the -constant on the right, as in: - - if (a == 1) { - /* Reads like: "If a equals 1" */ - do_something(); - } - -Rationale: Yoda conditions (as in 'if (1 == a)') are awkward to read. -Besides, good compilers already warn users when '==' is mis-typed as '=', -even when the constant is on the right. - -7. Comment style - -We use traditional C-style /* */ comments and avoid // comments. - -Rationale: The // form is valid in C99, so this is purely a matter of -consistency of style. The checkpatch script will warn you about this. - -Multiline comment blocks should have a row of stars on the left, -and the initial /* and terminating */ both on their own lines: - /* - * like - * this - */ -This is the same format required by the Linux kernel coding style. - -(Some of the existing comments in the codebase use the GNU Coding -Standards form which does not have stars on the left, or other -variations; avoid these when writing new comments, but don't worry -about converting to the preferred form unless you're editing that -comment anyway.) - -Rationale: Consistency, and ease of visually picking out a multiline -comment from the surrounding code. - -8. trace-events style - -8.1 0x prefix - -In trace-events files, use a '0x' prefix to specify hex numbers, as in: - -some_trace(unsigned x, uint64_t y) "x 0x%x y 0x" PRIx64 - -An exception is made for groups of numbers that are hexadecimal by -convention and separated by the symbols '.', '/', ':', or ' ' (such as -PCI bus id): - -another_trace(int cssid, int ssid, int dev_num) "bus id: %x.%x.%04x" - -However, you can use '0x' for such groups if you want. Anyway, be sure that -it is obvious that numbers are in hex, ex.: - -data_dump(uint8_t c1, uint8_t c2, uint8_t c3) "bytes (in hex): %02x %02x %02x" - -Rationale: hex numbers are hard to read in logs when there is no 0x prefix, -especially when (occasionally) the representation doesn't contain any letters -and especially in one line with other decimal numbers. Number groups are allowed -to not use '0x' because for some things notations like %x.%x.%x are used not -only in Qemu. Also dumping raw data bytes with '0x' is less readable. - -8.2 '#' printf flag - -Do not use printf flag '#', like '%#x'. - -Rationale: there are two ways to add a '0x' prefix to printed number: '0x%...' -and '%#...'. For consistency the only one way should be used. Arguments for -'0x%' are: - - it is more popular - - '%#' omits the 0x for the value 0 which makes output inconsistent diff --git a/CODING_STYLE.rst b/CODING_STYLE.rst new file mode 100644 index 0000000000..427699e0e4 --- /dev/null +++ b/CODING_STYLE.rst @@ -0,0 +1,641 @@ +================= +QEMU Coding Style +================= + +.. contents:: Table of Contents + +Please use the script checkpatch.pl in the scripts directory to check +patches before submitting. + +Formatting and style +******************** + +Whitespace +========== + +Of course, the most important aspect in any coding style is whitespace. +Crusty old coders who have trouble spotting the glasses on their noses +can tell the difference between a tab and eight spaces from a distance +of approximately fifteen parsecs. Many a flamewar has been fought and +lost on this issue. + +QEMU indents are four spaces. Tabs are never used, except in Makefiles +where they have been irreversibly coded into the syntax. +Spaces of course are superior to tabs because: + +* You have just one way to specify whitespace, not two. Ambiguity breeds + mistakes. +* The confusion surrounding 'use tabs to indent, spaces to justify' is gone. +* Tab indents push your code to the right, making your screen seriously + unbalanced. +* Tabs will be rendered incorrectly on editors who are misconfigured not + to use tab stops of eight positions. +* Tabs are rendered badly in patches, causing off-by-one errors in almost + every line. +* It is the QEMU coding style. + +Do not leave whitespace dangling off the ends of lines. + +Multiline Indent +---------------- + +There are several places where indent is necessary: + +* if/else +* while/for +* function definition & call + +When breaking up a long line to fit within line width, we need a proper indent +for the following lines. + +In case of if/else, while/for, align the secondary lines just after the +opening parenthesis of the first. + +For example: + +.. code-block:: c + + if (a == 1 && + b == 2) { + + while (a == 1 && + b == 2) { + +In case of function, there are several variants: + +* 4 spaces indent from the beginning +* align the secondary lines just after the opening parenthesis of the first + +For example: + +.. code-block:: c + + do_something(x, y, + z); + + do_something(x, y, + z); + + do_something(x, do_another(y, + z)); + +Line width +========== + +Lines should be 80 characters; try not to make them longer. + +Sometimes it is hard to do, especially when dealing with QEMU subsystems +that use long function or symbol names. Even in that case, do not make +lines much longer than 80 characters. + +Rationale: + +* Some people like to tile their 24" screens with a 6x4 matrix of 80x24 + xterms and use vi in all of them. The best way to punish them is to + let them keep doing it. +* Code and especially patches is much more readable if limited to a sane + line length. Eighty is traditional. +* The four-space indentation makes the most common excuse ("But look + at all that white space on the left!") moot. +* It is the QEMU coding style. + +Naming +====== + +Variables are lower_case_with_underscores; easy to type and read. Structured +type names are in CamelCase; harder to type but standing out. Enum type +names and function type names should also be in CamelCase. Scalar type +names are lower_case_with_underscores_ending_with_a_t, like the POSIX +uint64_t and family. Note that this last convention contradicts POSIX +and is therefore likely to be changed. + +When wrapping standard library functions, use the prefix ``qemu_`` to alert +readers that they are seeing a wrapped version; otherwise avoid this prefix. + +Block structure +=============== + +Every indented statement is braced; even if the block contains just one +statement. The opening brace is on the line that contains the control +flow statement that introduces the new block; the closing brace is on the +same line as the else keyword, or on a line by itself if there is no else +keyword. Example: + +.. code-block:: c + + if (a == 5) { + printf("a was 5.\n"); + } else if (a == 6) { + printf("a was 6.\n"); + } else { + printf("a was something else entirely.\n"); + } + +Note that 'else if' is considered a single statement; otherwise a long if/ +else if/else if/.../else sequence would need an indent for every else +statement. + +An exception is the opening brace for a function; for reasons of tradition +and clarity it comes on a line by itself: + +.. code-block:: c + + void a_function(void) + { + do_something(); + } + +Rationale: a consistent (except for functions...) bracing style reduces +ambiguity and avoids needless churn when lines are added or removed. +Furthermore, it is the QEMU coding style. + +Declarations +============ + +Mixed declarations (interleaving statements and declarations within +blocks) are generally not allowed; declarations should be at the beginning +of blocks. + +Every now and then, an exception is made for declarations inside a +#ifdef or #ifndef block: if the code looks nicer, such declarations can +be placed at the top of the block even if there are statements above. +On the other hand, however, it's often best to move that #ifdef/#ifndef +block to a separate function altogether. + +Conditional statements +====================== + +When comparing a variable for (in)equality with a constant, list the +constant on the right, as in: + +.. code-block:: c + + if (a == 1) { + /* Reads like: "If a equals 1" */ + do_something(); + } + +Rationale: Yoda conditions (as in 'if (1 == a)') are awkward to read. +Besides, good compilers already warn users when '==' is mis-typed as '=', +even when the constant is on the right. + +Comment style +============= + +We use traditional C-style /``*`` ``*``/ comments and avoid // comments. + +Rationale: The // form is valid in C99, so this is purely a matter of +consistency of style. The checkpatch script will warn you about this. + +Multiline comment blocks should have a row of stars on the left, +and the initial /``*`` and terminating ``*``/ both on their own lines: + +.. code-block:: c + + /* + * like + * this + */ + +This is the same format required by the Linux kernel coding style. + +(Some of the existing comments in the codebase use the GNU Coding +Standards form which does not have stars on the left, or other +variations; avoid these when writing new comments, but don't worry +about converting to the preferred form unless you're editing that +comment anyway.) + +Rationale: Consistency, and ease of visually picking out a multiline +comment from the surrounding code. + +Language usage +************** + +Preprocessor +============ + +Variadic macros +--------------- + +For variadic macros, stick with this C99-like syntax: + +.. code-block:: c + + #define DPRINTF(fmt, ...) \ + do { printf("IRQ: " fmt, ## __VA_ARGS__); } while (0) + +Include directives +------------------ + +Order include directives as follows: + +.. code-block:: c + + #include "qemu/osdep.h" /* Always first... */ + #include <...> /* then system headers... */ + #include "..." /* and finally QEMU headers. */ + +The "qemu/osdep.h" header contains preprocessor macros that affect the behavior +of core system headers like <stdint.h>. It must be the first include so that +core system headers included by external libraries get the preprocessor macros +that QEMU depends on. + +Do not include "qemu/osdep.h" from header files since the .c file will have +already included it. + +C types +======= + +It should be common sense to use the right type, but we have collected +a few useful guidelines here. + +Scalars +------- + +If you're using "int" or "long", odds are good that there's a better type. +If a variable is counting something, it should be declared with an +unsigned type. + +If it's host memory-size related, size_t should be a good choice (use +ssize_t only if required). Guest RAM memory offsets must use ram_addr_t, +but only for RAM, it may not cover whole guest address space. + +If it's file-size related, use off_t. +If it's file-offset related (i.e., signed), use off_t. +If it's just counting small numbers use "unsigned int"; +(on all but oddball embedded systems, you can assume that that +type is at least four bytes wide). + +In the event that you require a specific width, use a standard type +like int32_t, uint32_t, uint64_t, etc. The specific types are +mandatory for VMState fields. + +Don't use Linux kernel internal types like u32, __u32 or __le32. + +Use hwaddr for guest physical addresses except pcibus_t +for PCI addresses. In addition, ram_addr_t is a QEMU internal address +space that maps guest RAM physical addresses into an intermediate +address space that can map to host virtual address spaces. Generally +speaking, the size of guest memory can always fit into ram_addr_t but +it would not be correct to store an actual guest physical address in a +ram_addr_t. + +For CPU virtual addresses there are several possible types. +vaddr is the best type to use to hold a CPU virtual address in +target-independent code. It is guaranteed to be large enough to hold a +virtual address for any target, and it does not change size from target +to target. It is always unsigned. +target_ulong is a type the size of a virtual address on the CPU; this means +it may be 32 or 64 bits depending on which target is being built. It should +therefore be used only in target-specific code, and in some +performance-critical built-per-target core code such as the TLB code. +There is also a signed version, target_long. +abi_ulong is for the ``*``-user targets, and represents a type the size of +'void ``*``' in that target's ABI. (This may not be the same as the size of a +full CPU virtual address in the case of target ABIs which use 32 bit pointers +on 64 bit CPUs, like sparc32plus.) Definitions of structures that must match +the target's ABI must use this type for anything that on the target is defined +to be an 'unsigned long' or a pointer type. +There is also a signed version, abi_long. + +Of course, take all of the above with a grain of salt. If you're about +to use some system interface that requires a type like size_t, pid_t or +off_t, use matching types for any corresponding variables. + +Also, if you try to use e.g., "unsigned int" as a type, and that +conflicts with the signedness of a related variable, sometimes +it's best just to use the *wrong* type, if "pulling the thread" +and fixing all related variables would be too invasive. + +Finally, while using descriptive types is important, be careful not to +go overboard. If whatever you're doing causes warnings, or requires +casts, then reconsider or ask for help. + +Pointers +-------- + +Ensure that all of your pointers are "const-correct". +Unless a pointer is used to modify the pointed-to storage, +give it the "const" attribute. That way, the reader knows +up-front that this is a read-only pointer. Perhaps more +importantly, if we're diligent about this, when you see a non-const +pointer, you're guaranteed that it is used to modify the storage +it points to, or it is aliased to another pointer that is. + +Typedefs +-------- + +Typedefs are used to eliminate the redundant 'struct' keyword, since type +names have a different style than other identifiers ("CamelCase" versus +"snake_case"). Each named struct type should have a CamelCase name and a +corresponding typedef. + +Since certain C compilers choke on duplicated typedefs, you should avoid +them and declare a typedef only in one header file. For common types, +you can use "include/qemu/typedefs.h" for example. However, as a matter +of convenience it is also perfectly fine to use forward struct +definitions instead of typedefs in headers and function prototypes; this +avoids problems with duplicated typedefs and reduces the need to include +headers from other headers. + +Reserved namespaces in C and POSIX +---------------------------------- + +Underscore capital, double underscore, and underscore 't' suffixes should be +avoided. + +Low level memory management +=========================== + +Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign +APIs is not allowed in the QEMU codebase. Instead of these routines, +use the GLib memory allocation routines g_malloc/g_malloc0/g_new/ +g_new0/g_realloc/g_free or QEMU's qemu_memalign/qemu_blockalign/qemu_vfree +APIs. + +Please note that g_malloc will exit on allocation failure, so there +is no need to test for failure (as you would have to with malloc). +Calling g_malloc with a zero size is valid and will return NULL. + +Prefer g_new(T, n) instead of g_malloc(sizeof(T) ``*`` n) for the following +reasons: + +* It catches multiplication overflowing size_t; +* It returns T ``*`` instead of void ``*``, letting compiler catch more type errors. + +Declarations like + +.. code-block:: c + + T *v = g_malloc(sizeof(*v)) + +are acceptable, though. + +Memory allocated by qemu_memalign or qemu_blockalign must be freed with +qemu_vfree, since breaking this will cause problems on Win32. + +String manipulation +=================== + +Do not use the strncpy function. As mentioned in the man page, it does *not* +guarantee a NULL-terminated buffer, which makes it extremely dangerous to use. +It also zeros trailing destination bytes out to the specified length. Instead, +use this similar function when possible, but note its different signature: + +.. code-block:: c + + void pstrcpy(char *dest, int dest_buf_size, const char *src) + +Don't use strcat because it can't check for buffer overflows, but: + +.. code-block:: c + + char *pstrcat(char *buf, int buf_size, const char *s) + +The same limitation exists with sprintf and vsprintf, so use snprintf and +vsnprintf. + +QEMU provides other useful string functions: + +.. code-block:: c + + int strstart(const char *str, const char *val, const char **ptr) + int stristart(const char *str, const char *val, const char **ptr) + int qemu_strnlen(const char *s, int max_len) + +There are also replacement character processing macros for isxyz and toxyz, +so instead of e.g. isalnum you should use qemu_isalnum. + +Because of the memory management rules, you must use g_strdup/g_strndup +instead of plain strdup/strndup. + +Printf-style functions +====================== + +Whenever you add a new printf-style function, i.e., one with a format +string argument and following "..." in its prototype, be sure to use +gcc's printf attribute directive in the prototype. + +This makes it so gcc's -Wformat and -Wformat-security options can do +their jobs and cross-check format strings with the number and types +of arguments. + +C standard, implementation defined and undefined behaviors +========================================================== + +C code in QEMU should be written to the C99 language specification. A copy +of the final version of the C99 standard with corrigenda TC1, TC2, and TC3 +included, formatted as a draft, can be downloaded from: + + `<http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf>`_ + +The C language specification defines regions of undefined behavior and +implementation defined behavior (to give compiler authors enough leeway to +produce better code). In general, code in QEMU should follow the language +specification and avoid both undefined and implementation defined +constructs. ("It works fine on the gcc I tested it with" is not a valid +argument...) However there are a few areas where we allow ourselves to +assume certain behaviors because in practice all the platforms we care about +behave in the same way and writing strictly conformant code would be +painful. These are: + +* you may assume that integers are 2s complement representation +* you may assume that right shift of a signed integer duplicates + the sign bit (ie it is an arithmetic shift, not a logical shift) + +In addition, QEMU assumes that the compiler does not use the latitude +given in C99 and C11 to treat aspects of signed '<<' as undefined, as +documented in the GNU Compiler Collection manual starting at version 4.0. + +Automatic memory deallocation +============================= + +QEMU has a mandatory dependency either the GCC or CLang compiler. As +such it has the freedom to make use of a C language extension for +automatically running a cleanup function when a stack variable goes +out of scope. This can be used to simplify function cleanup paths, +often allowing many goto jumps to be eliminated, through automatic +free'ing of memory. + +The GLib2 library provides a number of functions/macros for enabling +automatic cleanup: + + `<https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html>`_ + +Most notably: + +* g_autofree - will invoke g_free() on the variable going out of scope + +* g_autoptr - for structs / objects, will invoke the cleanup func created + by a previous use of G_DEFINE_AUTOPTR_CLEANUP_FUNC. This is + supported for most GLib data types and GObjects + +For example, instead of + +.. code-block:: c + + int somefunc(void) { + int ret = -1; + char *foo = g_strdup_printf("foo%", "wibble"); + GList *bar = ..... + + if (eek) { + goto cleanup; + } + + ret = 0; + + cleanup: + g_free(foo); + g_list_free(bar); + return ret; + } + +Using g_autofree/g_autoptr enables the code to be written as: + +.. code-block:: c + + int somefunc(void) { + g_autofree char *foo = g_strdup_printf("foo%", "wibble"); + g_autoptr (GList) bar = ..... + + if (eek) { + return -1; + } + + return 0; + } + +While this generally results in simpler, less leak-prone code, there +are still some caveats to beware of + +* Variables declared with g_auto* MUST always be initialized, + otherwise the cleanup function will use uninitialized stack memory + +* If a variable declared with g_auto* holds a value which must + live beyond the life of the function, that value must be saved + and the original variable NULL'd out. This can be simpler using + g_steal_pointer + + +.. code-block:: c + + char *somefunc(void) { + g_autofree char *foo = g_strdup_printf("foo%", "wibble"); + g_autoptr (GList) bar = ..... + + if (eek) { + return NULL; + } + + return g_steal_pointer(&foo); + } + + +QEMU Specific Idioms +******************** + +Error handling and reporting +============================ + +Reporting errors to the human user +---------------------------------- + +Do not use printf(), fprintf() or monitor_printf(). Instead, use +error_report() or error_vreport() from error-report.h. This ensures the +error is reported in the right place (current monitor or stderr), and in +a uniform format. + +Use error_printf() & friends to print additional information. + +error_report() prints the current location. In certain common cases +like command line parsing, the current location is tracked +automatically. To manipulate it manually, use the loc_``*``() from +error-report.h. + +Propagating errors +------------------ + +An error can't always be reported to the user right where it's detected, +but often needs to be propagated up the call chain to a place that can +handle it. This can be done in various ways. + +The most flexible one is Error objects. See error.h for usage +information. + +Use the simplest suitable method to communicate success / failure to +callers. Stick to common methods: non-negative on success / -1 on +error, non-negative / -errno, non-null / null, or Error objects. + +Example: when a function returns a non-null pointer on success, and it +can fail only in one way (as far as the caller is concerned), returning +null on failure is just fine, and certainly simpler and a lot easier on +the eyes than propagating an Error object through an Error ``*````*`` parameter. + +Example: when a function's callers need to report details on failure +only the function really knows, use Error ``*````*``, and set suitable errors. + +Do not report an error to the user when you're also returning an error +for somebody else to handle. Leave the reporting to the place that +consumes the error returned. + +Handling errors +--------------- + +Calling exit() is fine when handling configuration errors during +startup. It's problematic during normal operation. In particular, +monitor commands should never exit(). + +Do not call exit() or abort() to handle an error that can be triggered +by the guest (e.g., some unimplemented corner case in guest code +translation or device emulation). Guests should not be able to +terminate QEMU. + +Note that &error_fatal is just another way to exit(1), and &error_abort +is just another way to abort(). + + +trace-events style +================== + +0x prefix +--------- + +In trace-events files, use a '0x' prefix to specify hex numbers, as in: + +.. code-block:: + + some_trace(unsigned x, uint64_t y) "x 0x%x y 0x" PRIx64 + +An exception is made for groups of numbers that are hexadecimal by +convention and separated by the symbols '.', '/', ':', or ' ' (such as +PCI bus id): + +.. code-block:: + + another_trace(int cssid, int ssid, int dev_num) "bus id: %x.%x.%04x" + +However, you can use '0x' for such groups if you want. Anyway, be sure that +it is obvious that numbers are in hex, ex.: + +.. code-block:: + + data_dump(uint8_t c1, uint8_t c2, uint8_t c3) "bytes (in hex): %02x %02x %02x" + +Rationale: hex numbers are hard to read in logs when there is no 0x prefix, +especially when (occasionally) the representation doesn't contain any letters +and especially in one line with other decimal numbers. Number groups are allowed +to not use '0x' because for some things notations like %x.%x.%x are used not +only in Qemu. Also dumping raw data bytes with '0x' is less readable. + +'#' printf flag +--------------- + +Do not use printf flag '#', like '%#x'. + +Rationale: there are two ways to add a '0x' prefix to printed number: '0x%...' +and '%#...'. For consistency the only one way should be used. Arguments for +'0x%' are: + +* it is more popular +* '%#' omits the 0x for the value 0 which makes output inconsistent diff --git a/HACKING b/HACKING deleted file mode 100644 index 097d482603..0000000000 --- a/HACKING +++ /dev/null @@ -1,257 +0,0 @@ -1. Preprocessor - -1.1. Variadic macros - -For variadic macros, stick with this C99-like syntax: - -#define DPRINTF(fmt, ...) \ - do { printf("IRQ: " fmt, ## __VA_ARGS__); } while (0) - -1.2. Include directives - -Order include directives as follows: - -#include "qemu/osdep.h" /* Always first... */ -#include <...> /* then system headers... */ -#include "..." /* and finally QEMU headers. */ - -The "qemu/osdep.h" header contains preprocessor macros that affect the behavior -of core system headers like <stdint.h>. It must be the first include so that -core system headers included by external libraries get the preprocessor macros -that QEMU depends on. - -Do not include "qemu/osdep.h" from header files since the .c file will have -already included it. - -2. C types - -It should be common sense to use the right type, but we have collected -a few useful guidelines here. - -2.1. Scalars - -If you're using "int" or "long", odds are good that there's a better type. -If a variable is counting something, it should be declared with an -unsigned type. - -If it's host memory-size related, size_t should be a good choice (use -ssize_t only if required). Guest RAM memory offsets must use ram_addr_t, -but only for RAM, it may not cover whole guest address space. - -If it's file-size related, use off_t. -If it's file-offset related (i.e., signed), use off_t. -If it's just counting small numbers use "unsigned int"; -(on all but oddball embedded systems, you can assume that that -type is at least four bytes wide). - -In the event that you require a specific width, use a standard type -like int32_t, uint32_t, uint64_t, etc. The specific types are -mandatory for VMState fields. - -Don't use Linux kernel internal types like u32, __u32 or __le32. - -Use hwaddr for guest physical addresses except pcibus_t -for PCI addresses. In addition, ram_addr_t is a QEMU internal address -space that maps guest RAM physical addresses into an intermediate -address space that can map to host virtual address spaces. Generally -speaking, the size of guest memory can always fit into ram_addr_t but -it would not be correct to store an actual guest physical address in a -ram_addr_t. - -For CPU virtual addresses there are several possible types. -vaddr is the best type to use to hold a CPU virtual address in -target-independent code. It is guaranteed to be large enough to hold a -virtual address for any target, and it does not change size from target -to target. It is always unsigned. -target_ulong is a type the size of a virtual address on the CPU; this means -it may be 32 or 64 bits depending on which target is being built. It should -therefore be used only in target-specific code, and in some -performance-critical built-per-target core code such as the TLB code. -There is also a signed version, target_long. -abi_ulong is for the *-user targets, and represents a type the size of -'void *' in that target's ABI. (This may not be the same as the size of a -full CPU virtual address in the case of target ABIs which use 32 bit pointers -on 64 bit CPUs, like sparc32plus.) Definitions of structures that must match -the target's ABI must use this type for anything that on the target is defined -to be an 'unsigned long' or a pointer type. -There is also a signed version, abi_long. - -Of course, take all of the above with a grain of salt. If you're about -to use some system interface that requires a type like size_t, pid_t or -off_t, use matching types for any corresponding variables. - -Also, if you try to use e.g., "unsigned int" as a type, and that -conflicts with the signedness of a related variable, sometimes -it's best just to use the *wrong* type, if "pulling the thread" -and fixing all related variables would be too invasive. - -Finally, while using descriptive types is important, be careful not to -go overboard. If whatever you're doing causes warnings, or requires -casts, then reconsider or ask for help. - -2.2. Pointers - -Ensure that all of your pointers are "const-correct". -Unless a pointer is used to modify the pointed-to storage, -give it the "const" attribute. That way, the reader knows -up-front that this is a read-only pointer. Perhaps more -importantly, if we're diligent about this, when you see a non-const -pointer, you're guaranteed that it is used to modify the storage -it points to, or it is aliased to another pointer that is. - -2.3. Typedefs - -Typedefs are used to eliminate the redundant 'struct' keyword, since type -names have a different style than other identifiers ("CamelCase" versus -"snake_case"). Each named struct type should have a CamelCase name and a -corresponding typedef. - -Since certain C compilers choke on duplicated typedefs, you should avoid -them and declare a typedef only in one header file. For common types, -you can use "include/qemu/typedefs.h" for example. However, as a matter -of convenience it is also perfectly fine to use forward struct -definitions instead of typedefs in headers and function prototypes; this -avoids problems with duplicated typedefs and reduces the need to include -headers from other headers. - -2.4. Reserved namespaces in C and POSIX -Underscore capital, double underscore, and underscore 't' suffixes should be -avoided. - -3. Low level memory management - -Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign -APIs is not allowed in the QEMU codebase. Instead of these routines, -use the GLib memory allocation routines g_malloc/g_malloc0/g_new/ -g_new0/g_realloc/g_free or QEMU's qemu_memalign/qemu_blockalign/qemu_vfree -APIs. - -Please note that g_malloc will exit on allocation failure, so there -is no need to test for failure (as you would have to with malloc). -Calling g_malloc with a zero size is valid and will return NULL. - -Prefer g_new(T, n) instead of g_malloc(sizeof(T) * n) for the following -reasons: - - a. It catches multiplication overflowing size_t; - b. It returns T * instead of void *, letting compiler catch more type - errors. - -Declarations like T *v = g_malloc(sizeof(*v)) are acceptable, though. - -Memory allocated by qemu_memalign or qemu_blockalign must be freed with -qemu_vfree, since breaking this will cause problems on Win32. - -4. String manipulation - -Do not use the strncpy function. As mentioned in the man page, it does *not* -guarantee a NULL-terminated buffer, which makes it extremely dangerous to use. -It also zeros trailing destination bytes out to the specified length. Instead, -use this similar function when possible, but note its different signature: -void pstrcpy(char *dest, int dest_buf_size, const char *src) - -Don't use strcat because it can't check for buffer overflows, but: -char *pstrcat(char *buf, int buf_size, const char *s) - -The same limitation exists with sprintf and vsprintf, so use snprintf and -vsnprintf. - -QEMU provides other useful string functions: -int strstart(const char *str, const char *val, const char **ptr) -int stristart(const char *str, const char *val, const char **ptr) -int qemu_strnlen(const char *s, int max_len) - -There are also replacement character processing macros for isxyz and toxyz, -so instead of e.g. isalnum you should use qemu_isalnum. - -Because of the memory management rules, you must use g_strdup/g_strndup -instead of plain strdup/strndup. - -5. Printf-style functions - -Whenever you add a new printf-style function, i.e., one with a format -string argument and following "..." in its prototype, be sure to use -gcc's printf attribute directive in the prototype. - -This makes it so gcc's -Wformat and -Wformat-security options can do -their jobs and cross-check format strings with the number and types -of arguments. - -6. C standard, implementation defined and undefined behaviors - -C code in QEMU should be written to the C99 language specification. A copy -of the final version of the C99 standard with corrigenda TC1, TC2, and TC3 -included, formatted as a draft, can be downloaded from: - http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf - -The C language specification defines regions of undefined behavior and -implementation defined behavior (to give compiler authors enough leeway to -produce better code). In general, code in QEMU should follow the language -specification and avoid both undefined and implementation defined -constructs. ("It works fine on the gcc I tested it with" is not a valid -argument...) However there are a few areas where we allow ourselves to -assume certain behaviors because in practice all the platforms we care about -behave in the same way and writing strictly conformant code would be -painful. These are: - * you may assume that integers are 2s complement representation - * you may assume that right shift of a signed integer duplicates - the sign bit (ie it is an arithmetic shift, not a logical shift) - -In addition, QEMU assumes that the compiler does not use the latitude -given in C99 and C11 to treat aspects of signed '<<' as undefined, as -documented in the GNU Compiler Collection manual starting at version 4.0. - -7. Error handling and reporting - -7.1 Reporting errors to the human user - -Do not use printf(), fprintf() or monitor_printf(). Instead, use -error_report() or error_vreport() from error-report.h. This ensures the -error is reported in the right place (current monitor or stderr), and in -a uniform format. - -Use error_printf() & friends to print additional information. - -error_report() prints the current location. In certain common cases -like command line parsing, the current location is tracked -automatically. To manipulate it manually, use the loc_*() from -error-report.h. - -7.2 Propagating errors - -An error can't always be reported to the user right where it's detected, -but often needs to be propagated up the call chain to a place that can -handle it. This can be done in various ways. - -The most flexible one is Error objects. See error.h for usage -information. - -Use the simplest suitable method to communicate success / failure to -callers. Stick to common methods: non-negative on success / -1 on -error, non-negative / -errno, non-null / null, or Error objects. - -Example: when a function returns a non-null pointer on success, and it -can fail only in one way (as far as the caller is concerned), returning -null on failure is just fine, and certainly simpler and a lot easier on -the eyes than propagating an Error object through an Error ** parameter. - -Example: when a function's callers need to report details on failure -only the function really knows, use Error **, and set suitable errors. - -Do not report an error to the user when you're also returning an error -for somebody else to handle. Leave the reporting to the place that -consumes the error returned. - -7.3 Handling errors - -Calling exit() is fine when handling configuration errors during -startup. It's problematic during normal operation. In particular, -monitor commands should never exit(). - -Do not call exit() or abort() to handle an error that can be triggered -by the guest (e.g., some unimplemented corner case in guest code -translation or device emulation). Guests should not be able to -terminate QEMU. - -Note that &error_fatal is just another way to exit(1), and &error_abort -is just another way to abort(). diff --git a/MAINTAINERS b/MAINTAINERS index ef6c01084b..50eaf005f4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -910,6 +910,13 @@ F: hw/char/mcf_uart.c F: hw/net/mcf_fec.c F: include/hw/m68k/mcf*.h +NeXTcube +M: Thomas Huth <huth@tuxfamily.org> +S: Odd Fixes +F: hw/m68k/next-*.c +F: hw/display/next-fb.c +F: include/hw/m68k/next-cube.h + MicroBlaze Machines ------------------- petalogix_s3adsp1800 @@ -1890,6 +1897,7 @@ M: Paolo Bonzini <pbonzini@redhat.com> S: Supported F: include/exec/ioport.h F: ioport.c +F: include/exec/memop.h F: include/exec/memory.h F: include/exec/ram_addr.h F: memory.c @@ -2078,7 +2086,7 @@ R: Paolo Bonzini <pbonzini@redhat.com> S: Maintained F: qtest.c F: accel/qtest.c -F: tests/libqtest.* +F: tests/libqtest* F: tests/libqos/ F: tests/*-test.c @@ -717,6 +717,7 @@ endef distclean: clean rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi qemu-monitor-info.texi + rm -f tests/tcg/config-*.mak rm -f config-all-devices.mak config-all-disas.mak config.status rm -f $(SUBDIR_DEVICES_MAK) rm -f po/*.mo tests/qemu-iotests/common.env diff --git a/Makefile.target b/Makefile.target index 933b27453a..5e916230c4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -39,9 +39,6 @@ endif PROGS=$(QEMU_PROG) $(QEMU_PROGW) STPFILES= -# Makefile Tests -include $(SRC_PATH)/tests/tcg/Makefile.include - config-target.h: config-target.h-timestamp config-target.h-timestamp: config-target.mak @@ -1,5 +1,6 @@ - QEMU README - =========== +=========== +QEMU README +=========== QEMU is a generic and open source machine & userspace emulator and virtualizer. @@ -37,6 +38,9 @@ QEMU is multi-platform software intended to be buildable on all modern Linux platforms, OS-X, Win32 (via the Mingw64 toolchain) and a variety of other UNIX targets. The simple steps to build QEMU are: + +.. code-block:: shell + mkdir build cd build ../configure @@ -44,9 +48,9 @@ of other UNIX targets. The simple steps to build QEMU are: Additional information can also be found online via the QEMU website: - https://qemu.org/Hosts/Linux - https://qemu.org/Hosts/Mac - https://qemu.org/Hosts/W32 +* `<https://qemu.org/Hosts/Linux>`_ +* `<https://qemu.org/Hosts/Mac>`_ +* `<https://qemu.org/Hosts/W32>`_ Submitting patches @@ -54,24 +58,29 @@ Submitting patches The QEMU source code is maintained under the GIT version control system. +.. code-block:: shell + git clone https://git.qemu.org/git/qemu.git When submitting patches, one common approach is to use 'git format-patch' and/or 'git send-email' to format & send the mail to the qemu-devel@nongnu.org mailing list. All patches submitted must contain a 'Signed-off-by' line from the author. Patches should follow the -guidelines set out in the HACKING and CODING_STYLE files. +guidelines set out in the CODING_STYLE.rst file. Additional information on submitting patches can be found online via the QEMU website - https://qemu.org/Contribute/SubmitAPatch - https://qemu.org/Contribute/TrivialPatches +* `<https://qemu.org/Contribute/SubmitAPatch>`_ +* `<https://qemu.org/Contribute/TrivialPatches>`_ The QEMU website is also maintained under source control. +.. code-block:: shell + git clone https://git.qemu.org/git/qemu-web.git - https://www.qemu.org/2017/02/04/the-new-qemu-website-is-up/ + +* `<https://www.qemu.org/2017/02/04/the-new-qemu-website-is-up/>`_ A 'git-publish' utility was created to make above process less cumbersome, and is highly recommended for making regular contributions, @@ -82,10 +91,12 @@ manually for once. For installation instructions, please go to - https://github.com/stefanha/git-publish +* `<https://github.com/stefanha/git-publish>`_ The workflow with 'git-publish' is: +.. code-block:: shell + $ git checkout master -b my-feature $ # work on new commits, add your 'Signed-off-by' lines to each $ git publish @@ -95,6 +106,8 @@ back to it in the future. Sending v2: +.. code-block:: shell + $ git checkout my-feature # same topic branch $ # making changes to the commits (using 'git rebase', for example) $ git publish @@ -109,7 +122,7 @@ The QEMU project uses Launchpad as its primary upstream bug tracker. Bugs found when running code built from QEMU git or upstream released sources should be reported via: - https://bugs.launchpad.net/qemu/ +* `<https://bugs.launchpad.net/qemu/>`_ If using QEMU via an operating system vendor pre-built binary package, it is preferable to report bugs to the vendor's own bug tracker first. If @@ -118,7 +131,7 @@ reported via launchpad. For additional information on bug reporting consult: - https://qemu.org/Contribute/ReportABug +* `<https://qemu.org/Contribute/ReportABug>`_ Contact @@ -127,13 +140,11 @@ Contact The QEMU community can be contacted in a number of ways, with the two main methods being email and IRC - - qemu-devel@nongnu.org - https://lists.nongnu.org/mailman/listinfo/qemu-devel - - #qemu on irc.oftc.net +* `<mailto:qemu-devel@nongnu.org>`_ +* `<https://lists.nongnu.org/mailman/listinfo/qemu-devel>`_ +* #qemu on irc.oftc.net Information on additional methods of contacting the community can be found online via the QEMU website: - https://qemu.org/Contribute/StartHere - --- End +* `<https://qemu.org/Contribute/StartHere>`_ diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index 5aaf186253..df9c838817 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -284,7 +284,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, #define GEN_ATOMIC_HELPER(X) \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ - ABI_TYPE val EXTRA_ARGS) \ + ABI_TYPE val EXTRA_ARGS) \ { \ ATOMIC_MMU_DECLS; \ DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index bb9897b25a..abae79650c 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -710,6 +710,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, hwaddr iotlb, xlat, sz, paddr_page; target_ulong vaddr_page; int asidx = cpu_asidx_from_attrs(cpu, attrs); + int wp_flags; assert_cpu_is_self(cpu); @@ -732,11 +733,12 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, address = vaddr_page; if (size < TARGET_PAGE_SIZE) { - /* - * Slow-path the TLB entries; we will repeat the MMU check and TLB - * fill on every access. - */ - address |= TLB_RECHECK; + /* Repeat the MMU check and TLB fill on every access. */ + address |= TLB_INVALID_MASK; + } + if (attrs.byte_swap) { + /* Force the access through the I/O slow path. */ + address |= TLB_MMIO; } if (!memory_region_is_ram(section->mr) && !memory_region_is_romd(section->mr)) { @@ -751,6 +753,8 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, code_address = address; iotlb = memory_region_section_get_iotlb(cpu, section, vaddr_page, paddr_page, xlat, prot, &address); + wp_flags = cpu_watchpoint_address_matches(cpu, vaddr_page, + TARGET_PAGE_SIZE); index = tlb_index(env, mmu_idx, vaddr_page); te = tlb_entry(env, mmu_idx, vaddr_page); @@ -804,6 +808,9 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, tn.addend = addend - vaddr_page; if (prot & PAGE_READ) { tn.addr_read = address; + if (wp_flags & BP_MEM_READ) { + tn.addr_read |= TLB_WATCHPOINT; + } } else { tn.addr_read = -1; } @@ -830,6 +837,9 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, if (prot & PAGE_WRITE_INV) { tn.addr_write |= TLB_INVALID_MASK; } + if (wp_flags & BP_MEM_WRITE) { + tn.addr_write |= TLB_WATCHPOINT; + } } copy_tlb_helper_locked(te, &tn); @@ -881,7 +891,7 @@ static void tlb_fill(CPUState *cpu, target_ulong addr, int size, static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, int mmu_idx, target_ulong addr, uintptr_t retaddr, - MMUAccessType access_type, int size) + MMUAccessType access_type, MemOp op) { CPUState *cpu = env_cpu(env); hwaddr mr_offset; @@ -891,6 +901,10 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, bool locked = false; MemTxResult r; + if (iotlbentry->attrs.byte_swap) { + op ^= MO_BSWAP; + } + section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); mr = section->mr; mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; @@ -906,14 +920,13 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, qemu_mutex_lock_iothread(); locked = true; } - r = memory_region_dispatch_read(mr, mr_offset, - &val, size, iotlbentry->attrs); + r = memory_region_dispatch_read(mr, mr_offset, &val, op, iotlbentry->attrs); if (r != MEMTX_OK) { hwaddr physaddr = mr_offset + section->offset_within_address_space - section->offset_within_region; - cpu_transaction_failed(cpu, physaddr, addr, size, access_type, + cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), access_type, mmu_idx, iotlbentry->attrs, r, retaddr); } if (locked) { @@ -925,7 +938,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, int mmu_idx, uint64_t val, target_ulong addr, - uintptr_t retaddr, int size) + uintptr_t retaddr, MemOp op) { CPUState *cpu = env_cpu(env); hwaddr mr_offset; @@ -934,6 +947,10 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, bool locked = false; MemTxResult r; + if (iotlbentry->attrs.byte_swap) { + op ^= MO_BSWAP; + } + section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); mr = section->mr; mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; @@ -947,15 +964,15 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, qemu_mutex_lock_iothread(); locked = true; } - r = memory_region_dispatch_write(mr, mr_offset, - val, size, iotlbentry->attrs); + r = memory_region_dispatch_write(mr, mr_offset, val, op, iotlbentry->attrs); if (r != MEMTX_OK) { hwaddr physaddr = mr_offset + section->offset_within_address_space - section->offset_within_region; - cpu_transaction_failed(cpu, physaddr, addr, size, MMU_DATA_STORE, - mmu_idx, iotlbentry->attrs, r, retaddr); + cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), + MMU_DATA_STORE, mmu_idx, iotlbentry->attrs, r, + retaddr); } if (locked) { qemu_mutex_unlock_iothread(); @@ -1015,10 +1032,15 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, victim_tlb_hit(env, mmu_idx, index, offsetof(CPUTLBEntry, TY), \ (ADDR) & TARGET_PAGE_MASK) -/* NOTE: this function can trigger an exception */ -/* NOTE2: the returned address is not exactly the physical address: it - * is actually a ram_addr_t (in system mode; the user mode emulation - * version of this function returns a guest virtual address). +/* + * Return a ram_addr_t for the virtual address for execution. + * + * Return -1 if we can't translate and execute from an entire page + * of RAM. This will force us to execute by loading and translating + * one insn at a time, without caching. + * + * NOTE: This function will trigger an exception if the page is + * not executable. */ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr) { @@ -1032,19 +1054,20 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr) tlb_fill(env_cpu(env), addr, 0, MMU_INST_FETCH, mmu_idx, 0); index = tlb_index(env, mmu_idx, addr); entry = tlb_entry(env, mmu_idx, addr); + + if (unlikely(entry->addr_code & TLB_INVALID_MASK)) { + /* + * The MMU protection covers a smaller range than a target + * page, so we must redo the MMU check for every insn. + */ + return -1; + } } assert(tlb_hit(entry->addr_code, addr)); } - if (unlikely(entry->addr_code & (TLB_RECHECK | TLB_MMIO))) { - /* - * Return -1 if we can't translate and execute from an entire - * page of RAM here, which will cause us to execute by loading - * and translating one insn at a time, without caching: - * - TLB_RECHECK: means the MMU protection covers a smaller range - * than a target page, so we must redo the MMU check every insn - * - TLB_MMIO: region is not backed by RAM - */ + if (unlikely(entry->addr_code & TLB_MMIO)) { + /* The region is not backed by RAM. */ return -1; } @@ -1052,25 +1075,70 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr) return qemu_ram_addr_from_host_nofail(p); } -/* Probe for whether the specified guest write access is permitted. - * If it is not permitted then an exception will be taken in the same - * way as if this were a real write access (and we will not return). - * Otherwise the function will return, and there will be a valid - * entry in the TLB for this access. +/* + * Probe for whether the specified guest access is permitted. If it is not + * permitted then an exception will be taken in the same way as if this + * were a real access (and we will not return). + * If the size is 0 or the page requires I/O access, returns NULL; otherwise, + * returns the address of the host page similar to tlb_vaddr_to_host(). */ -void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx, - uintptr_t retaddr) +void *probe_access(CPUArchState *env, target_ulong addr, int size, + MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { uintptr_t index = tlb_index(env, mmu_idx, addr); CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); + target_ulong tlb_addr; + size_t elt_ofs; + int wp_access; - if (!tlb_hit(tlb_addr_write(entry), addr)) { - /* TLB entry is for a different page */ - if (!VICTIM_TLB_HIT(addr_write, addr)) { - tlb_fill(env_cpu(env), addr, size, MMU_DATA_STORE, - mmu_idx, retaddr); + g_assert(-(addr | TARGET_PAGE_MASK) >= size); + + switch (access_type) { + case MMU_DATA_LOAD: + elt_ofs = offsetof(CPUTLBEntry, addr_read); + wp_access = BP_MEM_READ; + break; + case MMU_DATA_STORE: + elt_ofs = offsetof(CPUTLBEntry, addr_write); + wp_access = BP_MEM_WRITE; + break; + case MMU_INST_FETCH: + elt_ofs = offsetof(CPUTLBEntry, addr_code); + wp_access = BP_MEM_READ; + break; + default: + g_assert_not_reached(); + } + tlb_addr = tlb_read_ofs(entry, elt_ofs); + + if (unlikely(!tlb_hit(tlb_addr, addr))) { + if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, + addr & TARGET_PAGE_MASK)) { + tlb_fill(env_cpu(env), addr, size, access_type, mmu_idx, retaddr); + /* TLB resize via tlb_fill may have moved the entry. */ + index = tlb_index(env, mmu_idx, addr); + entry = tlb_entry(env, mmu_idx, addr); } + tlb_addr = tlb_read_ofs(entry, elt_ofs); + } + + if (!size) { + return NULL; } + + /* Handle watchpoints. */ + if (tlb_addr & TLB_WATCHPOINT) { + cpu_check_watchpoint(env_cpu(env), addr, size, + env_tlb(env)->d[mmu_idx].iotlb[index].attrs, + wp_access, retaddr); + } + + if (tlb_addr & (TLB_NOTDIRTY | TLB_MMIO)) { + /* I/O access */ + return NULL; + } + + return (void *)((uintptr_t)addr + entry->addend); } void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, @@ -1133,7 +1201,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, uintptr_t index = tlb_index(env, mmu_idx, addr); CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr); target_ulong tlb_addr = tlb_addr_write(tlbe); - TCGMemOp mop = get_memop(oi); + MemOp mop = get_memop(oi); int a_bits = get_alignment_bits(mop); int s_bits = mop & MO_SIZE; void *hostaddr; @@ -1169,7 +1237,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, } /* Notice an IO access or a needs-MMU-lookup access */ - if (unlikely(tlb_addr & (TLB_MMIO | TLB_RECHECK))) { + if (unlikely(tlb_addr & TLB_MMIO)) { /* There's really nothing that can be done to support this apart from stop-the-world. */ goto stop_the_world; @@ -1201,37 +1269,6 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, cpu_loop_exit_atomic(env_cpu(env), retaddr); } -#ifdef TARGET_WORDS_BIGENDIAN -#define NEED_BE_BSWAP 0 -#define NEED_LE_BSWAP 1 -#else -#define NEED_BE_BSWAP 1 -#define NEED_LE_BSWAP 0 -#endif - -/* - * Byte Swap Helper - * - * This should all dead code away depending on the build host and - * access type. - */ - -static inline uint64_t handle_bswap(uint64_t val, int size, bool big_endian) -{ - if ((big_endian && NEED_BE_BSWAP) || (!big_endian && NEED_LE_BSWAP)) { - switch (size) { - case 1: return val; - case 2: return bswap16(val); - case 4: return bswap32(val); - case 8: return bswap64(val); - default: - g_assert_not_reached(); - } - } else { - return val; - } -} - /* * Load Helpers * @@ -1246,7 +1283,7 @@ typedef uint64_t FullLoadHelper(CPUArchState *env, target_ulong addr, static inline uint64_t __attribute__((always_inline)) load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, - uintptr_t retaddr, size_t size, bool big_endian, bool code_read, + uintptr_t retaddr, MemOp op, bool code_read, FullLoadHelper *full_load) { uintptr_t mmu_idx = get_mmuidx(oi); @@ -1260,6 +1297,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, unsigned a_bits = get_alignment_bits(get_memop(oi)); void *haddr; uint64_t res; + size_t size = memop_size(op); /* Handle CPU specific unaligned behaviour */ if (addr & ((1 << a_bits) - 1)) { @@ -1277,37 +1315,36 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, entry = tlb_entry(env, mmu_idx, addr); } tlb_addr = code_read ? entry->addr_code : entry->addr_read; + tlb_addr &= ~TLB_INVALID_MASK; } - /* Handle an IO access. */ + /* Handle anything that isn't just a straight memory access. */ if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { + CPUIOTLBEntry *iotlbentry; + + /* For anything that is unaligned, recurse through full_load. */ if ((addr & (size - 1)) != 0) { goto do_unaligned_access; } - if (tlb_addr & TLB_RECHECK) { - /* - * This is a TLB_RECHECK access, where the MMU protection - * covers a smaller range than a target page, and we must - * repeat the MMU check here. This tlb_fill() call might - * longjump out if this access should cause a guest exception. - */ - tlb_fill(env_cpu(env), addr, size, - access_type, mmu_idx, retaddr); - index = tlb_index(env, mmu_idx, addr); - entry = tlb_entry(env, mmu_idx, addr); + iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; + + /* Handle watchpoints. */ + if (unlikely(tlb_addr & TLB_WATCHPOINT)) { + /* On watchpoint hit, this will longjmp out. */ + cpu_check_watchpoint(env_cpu(env), addr, size, + iotlbentry->attrs, BP_MEM_READ, retaddr); - tlb_addr = code_read ? entry->addr_code : entry->addr_read; - tlb_addr &= ~TLB_RECHECK; - if (!(tlb_addr & ~TARGET_PAGE_MASK)) { - /* RAM access */ + /* The backing page may or may not require I/O. */ + tlb_addr &= ~TLB_WATCHPOINT; + if ((tlb_addr & ~TARGET_PAGE_MASK) == 0) { goto do_aligned_access; } } - res = io_readx(env, &env_tlb(env)->d[mmu_idx].iotlb[index], - mmu_idx, addr, retaddr, access_type, size); - return handle_bswap(res, size, big_endian); + /* Handle I/O access. */ + return io_readx(env, iotlbentry, mmu_idx, addr, + retaddr, access_type, op); } /* Handle slow unaligned access (it spans two pages or IO). */ @@ -1324,7 +1361,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, r2 = full_load(env, addr2, oi, retaddr); shift = (addr & (size - 1)) * 8; - if (big_endian) { + if (memop_big_endian(op)) { /* Big-endian combine. */ res = (r1 << shift) | (r2 >> ((size * 8) - shift)); } else { @@ -1336,30 +1373,27 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, do_aligned_access: haddr = (void *)((uintptr_t)addr + entry->addend); - switch (size) { - case 1: + switch (op) { + case MO_UB: res = ldub_p(haddr); break; - case 2: - if (big_endian) { - res = lduw_be_p(haddr); - } else { - res = lduw_le_p(haddr); - } + case MO_BEUW: + res = lduw_be_p(haddr); break; - case 4: - if (big_endian) { - res = (uint32_t)ldl_be_p(haddr); - } else { - res = (uint32_t)ldl_le_p(haddr); - } + case MO_LEUW: + res = lduw_le_p(haddr); break; - case 8: - if (big_endian) { - res = ldq_be_p(haddr); - } else { - res = ldq_le_p(haddr); - } + case MO_BEUL: + res = (uint32_t)ldl_be_p(haddr); + break; + case MO_LEUL: + res = (uint32_t)ldl_le_p(haddr); + break; + case MO_BEQ: + res = ldq_be_p(haddr); + break; + case MO_LEQ: + res = ldq_le_p(haddr); break; default: g_assert_not_reached(); @@ -1381,8 +1415,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, static uint64_t full_ldub_mmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 1, false, false, - full_ldub_mmu); + return load_helper(env, addr, oi, retaddr, MO_UB, false, full_ldub_mmu); } tcg_target_ulong helper_ret_ldub_mmu(CPUArchState *env, target_ulong addr, @@ -1394,7 +1427,7 @@ tcg_target_ulong helper_ret_ldub_mmu(CPUArchState *env, target_ulong addr, static uint64_t full_le_lduw_mmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 2, false, false, + return load_helper(env, addr, oi, retaddr, MO_LEUW, false, full_le_lduw_mmu); } @@ -1407,7 +1440,7 @@ tcg_target_ulong helper_le_lduw_mmu(CPUArchState *env, target_ulong addr, static uint64_t full_be_lduw_mmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 2, true, false, + return load_helper(env, addr, oi, retaddr, MO_BEUW, false, full_be_lduw_mmu); } @@ -1420,7 +1453,7 @@ tcg_target_ulong helper_be_lduw_mmu(CPUArchState *env, target_ulong addr, static uint64_t full_le_ldul_mmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 4, false, false, + return load_helper(env, addr, oi, retaddr, MO_LEUL, false, full_le_ldul_mmu); } @@ -1433,7 +1466,7 @@ tcg_target_ulong helper_le_ldul_mmu(CPUArchState *env, target_ulong addr, static uint64_t full_be_ldul_mmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 4, true, false, + return load_helper(env, addr, oi, retaddr, MO_BEUL, false, full_be_ldul_mmu); } @@ -1446,14 +1479,14 @@ tcg_target_ulong helper_be_ldul_mmu(CPUArchState *env, target_ulong addr, uint64_t helper_le_ldq_mmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 8, false, false, + return load_helper(env, addr, oi, retaddr, MO_LEQ, false, helper_le_ldq_mmu); } uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 8, true, false, + return load_helper(env, addr, oi, retaddr, MO_BEQ, false, helper_be_ldq_mmu); } @@ -1499,7 +1532,7 @@ tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr, static inline void __attribute__((always_inline)) store_helper(CPUArchState *env, target_ulong addr, uint64_t val, - TCGMemOpIdx oi, uintptr_t retaddr, size_t size, bool big_endian) + TCGMemOpIdx oi, uintptr_t retaddr, MemOp op) { uintptr_t mmu_idx = get_mmuidx(oi); uintptr_t index = tlb_index(env, mmu_idx, addr); @@ -1508,6 +1541,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, const size_t tlb_off = offsetof(CPUTLBEntry, addr_write); unsigned a_bits = get_alignment_bits(get_memop(oi)); void *haddr; + size_t size = memop_size(op); /* Handle CPU specific unaligned behaviour */ if (addr & ((1 << a_bits) - 1)) { @@ -1527,35 +1561,32 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, tlb_addr = tlb_addr_write(entry) & ~TLB_INVALID_MASK; } - /* Handle an IO access. */ + /* Handle anything that isn't just a straight memory access. */ if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { + CPUIOTLBEntry *iotlbentry; + + /* For anything that is unaligned, recurse through byte stores. */ if ((addr & (size - 1)) != 0) { goto do_unaligned_access; } - if (tlb_addr & TLB_RECHECK) { - /* - * This is a TLB_RECHECK access, where the MMU protection - * covers a smaller range than a target page, and we must - * repeat the MMU check here. This tlb_fill() call might - * longjump out if this access should cause a guest exception. - */ - tlb_fill(env_cpu(env), addr, size, MMU_DATA_STORE, - mmu_idx, retaddr); - index = tlb_index(env, mmu_idx, addr); - entry = tlb_entry(env, mmu_idx, addr); + iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; + + /* Handle watchpoints. */ + if (unlikely(tlb_addr & TLB_WATCHPOINT)) { + /* On watchpoint hit, this will longjmp out. */ + cpu_check_watchpoint(env_cpu(env), addr, size, + iotlbentry->attrs, BP_MEM_WRITE, retaddr); - tlb_addr = tlb_addr_write(entry); - tlb_addr &= ~TLB_RECHECK; - if (!(tlb_addr & ~TARGET_PAGE_MASK)) { - /* RAM access */ + /* The backing page may or may not require I/O. */ + tlb_addr &= ~TLB_WATCHPOINT; + if ((tlb_addr & ~TARGET_PAGE_MASK) == 0) { goto do_aligned_access; } } - io_writex(env, &env_tlb(env)->d[mmu_idx].iotlb[index], mmu_idx, - handle_bswap(val, size, big_endian), - addr, retaddr, size); + /* Handle I/O access. */ + io_writex(env, iotlbentry, mmu_idx, val, addr, retaddr, op); return; } @@ -1567,6 +1598,8 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, uintptr_t index2; CPUTLBEntry *entry2; target_ulong page2, tlb_addr2; + size_t size2; + do_unaligned_access: /* * Ensure the second page is in the TLB. Note that the first page @@ -1574,14 +1607,33 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, * cannot evict the first. */ page2 = (addr + size) & TARGET_PAGE_MASK; + size2 = (addr + size) & ~TARGET_PAGE_MASK; index2 = tlb_index(env, mmu_idx, page2); entry2 = tlb_entry(env, mmu_idx, page2); tlb_addr2 = tlb_addr_write(entry2); - if (!tlb_hit_page(tlb_addr2, page2) - && !victim_tlb_hit(env, mmu_idx, index2, tlb_off, - page2 & TARGET_PAGE_MASK)) { - tlb_fill(env_cpu(env), page2, size, MMU_DATA_STORE, - mmu_idx, retaddr); + if (!tlb_hit_page(tlb_addr2, page2)) { + if (!victim_tlb_hit(env, mmu_idx, index2, tlb_off, page2)) { + tlb_fill(env_cpu(env), page2, size2, MMU_DATA_STORE, + mmu_idx, retaddr); + index2 = tlb_index(env, mmu_idx, page2); + entry2 = tlb_entry(env, mmu_idx, page2); + } + tlb_addr2 = tlb_addr_write(entry2); + } + + /* + * Handle watchpoints. Since this may trap, all checks + * must happen before any store. + */ + if (unlikely(tlb_addr & TLB_WATCHPOINT)) { + cpu_check_watchpoint(env_cpu(env), addr, size - size2, + env_tlb(env)->d[mmu_idx].iotlb[index].attrs, + BP_MEM_WRITE, retaddr); + } + if (unlikely(tlb_addr2 & TLB_WATCHPOINT)) { + cpu_check_watchpoint(env_cpu(env), page2, size2, + env_tlb(env)->d[mmu_idx].iotlb[index2].attrs, + BP_MEM_WRITE, retaddr); } /* @@ -1591,7 +1643,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, */ for (i = 0; i < size; ++i) { uint8_t val8; - if (big_endian) { + if (memop_big_endian(op)) { /* Big-endian extract. */ val8 = val >> (((size - 1) * 8) - (i * 8)); } else { @@ -1605,30 +1657,27 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, do_aligned_access: haddr = (void *)((uintptr_t)addr + entry->addend); - switch (size) { - case 1: + switch (op) { + case MO_UB: stb_p(haddr, val); break; - case 2: - if (big_endian) { - stw_be_p(haddr, val); - } else { - stw_le_p(haddr, val); - } + case MO_BEUW: + stw_be_p(haddr, val); break; - case 4: - if (big_endian) { - stl_be_p(haddr, val); - } else { - stl_le_p(haddr, val); - } + case MO_LEUW: + stw_le_p(haddr, val); break; - case 8: - if (big_endian) { - stq_be_p(haddr, val); - } else { - stq_le_p(haddr, val); - } + case MO_BEUL: + stl_be_p(haddr, val); + break; + case MO_LEUL: + stl_le_p(haddr, val); + break; + case MO_BEQ: + stq_be_p(haddr, val); + break; + case MO_LEQ: + stq_le_p(haddr, val); break; default: g_assert_not_reached(); @@ -1639,43 +1688,43 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, void helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, TCGMemOpIdx oi, uintptr_t retaddr) { - store_helper(env, addr, val, oi, retaddr, 1, false); + store_helper(env, addr, val, oi, retaddr, MO_UB); } void helper_le_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, TCGMemOpIdx oi, uintptr_t retaddr) { - store_helper(env, addr, val, oi, retaddr, 2, false); + store_helper(env, addr, val, oi, retaddr, MO_LEUW); } void helper_be_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, TCGMemOpIdx oi, uintptr_t retaddr) { - store_helper(env, addr, val, oi, retaddr, 2, true); + store_helper(env, addr, val, oi, retaddr, MO_BEUW); } void helper_le_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, TCGMemOpIdx oi, uintptr_t retaddr) { - store_helper(env, addr, val, oi, retaddr, 4, false); + store_helper(env, addr, val, oi, retaddr, MO_LEUL); } void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, TCGMemOpIdx oi, uintptr_t retaddr) { - store_helper(env, addr, val, oi, retaddr, 4, true); + store_helper(env, addr, val, oi, retaddr, MO_BEUL); } void helper_le_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, TCGMemOpIdx oi, uintptr_t retaddr) { - store_helper(env, addr, val, oi, retaddr, 8, false); + store_helper(env, addr, val, oi, retaddr, MO_LEQ); } void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, TCGMemOpIdx oi, uintptr_t retaddr) { - store_helper(env, addr, val, oi, retaddr, 8, true); + store_helper(env, addr, val, oi, retaddr, MO_BEQ); } /* First set of helpers allows passing in of OI and RETADDR. This makes @@ -1740,8 +1789,7 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, static uint64_t full_ldub_cmmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 1, false, true, - full_ldub_cmmu); + return load_helper(env, addr, oi, retaddr, MO_8, true, full_ldub_cmmu); } uint8_t helper_ret_ldb_cmmu(CPUArchState *env, target_ulong addr, @@ -1753,7 +1801,7 @@ uint8_t helper_ret_ldb_cmmu(CPUArchState *env, target_ulong addr, static uint64_t full_le_lduw_cmmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 2, false, true, + return load_helper(env, addr, oi, retaddr, MO_LEUW, true, full_le_lduw_cmmu); } @@ -1766,7 +1814,7 @@ uint16_t helper_le_ldw_cmmu(CPUArchState *env, target_ulong addr, static uint64_t full_be_lduw_cmmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 2, true, true, + return load_helper(env, addr, oi, retaddr, MO_BEUW, true, full_be_lduw_cmmu); } @@ -1779,7 +1827,7 @@ uint16_t helper_be_ldw_cmmu(CPUArchState *env, target_ulong addr, static uint64_t full_le_ldul_cmmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 4, false, true, + return load_helper(env, addr, oi, retaddr, MO_LEUL, true, full_le_ldul_cmmu); } @@ -1792,7 +1840,7 @@ uint32_t helper_le_ldl_cmmu(CPUArchState *env, target_ulong addr, static uint64_t full_be_ldul_cmmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 4, true, true, + return load_helper(env, addr, oi, retaddr, MO_BEUL, true, full_be_ldul_cmmu); } @@ -1805,13 +1853,13 @@ uint32_t helper_be_ldl_cmmu(CPUArchState *env, target_ulong addr, uint64_t helper_le_ldq_cmmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 8, false, true, + return load_helper(env, addr, oi, retaddr, MO_LEQ, true, helper_le_ldq_cmmu); } uint64_t helper_be_ldq_cmmu(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr) { - return load_helper(env, addr, oi, retaddr, 8, true, true, + return load_helper(env, addr, oi, retaddr, MO_BEQ, true, helper_be_ldq_cmmu); } diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 897d1571c4..71c4bf6477 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -188,6 +188,38 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info, g_assert_not_reached(); } +void *probe_access(CPUArchState *env, target_ulong addr, int size, + MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) +{ + int flags; + + g_assert(-(addr | TARGET_PAGE_MASK) >= size); + + switch (access_type) { + case MMU_DATA_STORE: + flags = PAGE_WRITE; + break; + case MMU_DATA_LOAD: + flags = PAGE_READ; + break; + case MMU_INST_FETCH: + flags = PAGE_EXEC; + break; + default: + g_assert_not_reached(); + } + + if (!guest_addr_valid(addr) || page_check_range(addr, size, flags) < 0) { + CPUState *cpu = env_cpu(env); + CPUClass *cc = CPU_GET_CLASS(cpu); + cc->tlb_fill(cpu, addr, size, access_type, MMU_USER_IDX, false, + retaddr); + g_assert_not_reached(); + } + + return size ? g2h(addr) : NULL; +} + #if defined(__i386__) #if defined(__NetBSD__) diff --git a/audio/audio.c b/audio/audio.c index 7d715332c9..e99fcd0694 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1412,8 +1412,9 @@ static AudioState *audio_init(Audiodev *dev, const char *name) drvname = AudiodevDriver_str(dev->driver); } else if (!QTAILQ_EMPTY(&audio_states)) { if (!legacy_config) { - dolog("You must specify an audiodev= for the device %s\n", name); - exit(1); + dolog("Device %s: audiodev default parameter is deprecated, please " + "specify audiodev=%s\n", name, + QTAILQ_FIRST(&audio_states)->dev->id); } return QTAILQ_FIRST(&audio_states); } else { @@ -1548,8 +1549,7 @@ CaptureVoiceOut *AUD_add_capture( if (!s) { if (!legacy_config) { - dolog("You must specify audiodev when trying to capture\n"); - return NULL; + dolog("Capturing without setting an audiodev is deprecated\n"); } s = audio_init(NULL, NULL); } @@ -1685,7 +1685,7 @@ void audio_create_pdos(Audiodev *dev) } \ if (!dev->u.driver.has_out) { \ dev->u.driver.out = g_malloc0( \ - sizeof(AudiodevAlsaPerDirectionOptions)); \ + sizeof(Audiodev##pdo_name##PerDirectionOptions)); \ dev->u.driver.has_out = true; \ } \ break diff --git a/backends/Makefile.objs b/backends/Makefile.objs index 981e8e122f..f0691116e8 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-y += rng.o rng-egd.o +common-obj-y += rng.o rng-egd.o rng-builtin.o common-obj-$(CONFIG_POSIX) += rng-random.o common-obj-$(CONFIG_TPM) += tpm.o diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index 29e55c9195..ecc15e3eb0 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -67,12 +67,12 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) uint64_t size; size = qemu_get_pmem_size(fb->mem_path, &local_err); - if (!size) { + if (local_err) { error_propagate(errp, local_err); return; } - if (backend->size > size) { + if (size && backend->size > size) { error_setg(errp, "size property %" PRIu64 " is larger than " "pmem file \"%s\" size %" PRIu64, backend->size, fb->mem_path, size); diff --git a/backends/rng-builtin.c b/backends/rng-builtin.c new file mode 100644 index 0000000000..ba1b8d66b8 --- /dev/null +++ b/backends/rng-builtin.c @@ -0,0 +1,77 @@ +/* + * QEMU Builtin Random Number Generator Backend + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "sysemu/rng.h" +#include "qemu/main-loop.h" +#include "qemu/guest-random.h" + +#define RNG_BUILTIN(obj) OBJECT_CHECK(RngBuiltin, (obj), TYPE_RNG_BUILTIN) + +typedef struct RngBuiltin { + RngBackend parent; + QEMUBH *bh; +} RngBuiltin; + +static void rng_builtin_receive_entropy_bh(void *opaque) +{ + RngBuiltin *s = opaque; + + while (!QSIMPLEQ_EMPTY(&s->parent.requests)) { + RngRequest *req = QSIMPLEQ_FIRST(&s->parent.requests); + + qemu_guest_getrandom_nofail(req->data, req->size); + + req->receive_entropy(req->opaque, req->data, req->size); + + rng_backend_finalize_request(&s->parent, req); + } +} + +static void rng_builtin_request_entropy(RngBackend *b, RngRequest *req) +{ + RngBuiltin *s = RNG_BUILTIN(b); + + qemu_bh_schedule(s->bh); +} + +static void rng_builtin_init(Object *obj) +{ + RngBuiltin *s = RNG_BUILTIN(obj); + + s->bh = qemu_bh_new(rng_builtin_receive_entropy_bh, s); +} + +static void rng_builtin_finalize(Object *obj) +{ + RngBuiltin *s = RNG_BUILTIN(obj); + + qemu_bh_delete(s->bh); +} + +static void rng_builtin_class_init(ObjectClass *klass, void *data) +{ + RngBackendClass *rbc = RNG_BACKEND_CLASS(klass); + + rbc->request_entropy = rng_builtin_request_entropy; +} + +static const TypeInfo rng_builtin_info = { + .name = TYPE_RNG_BUILTIN, + .parent = TYPE_RNG_BACKEND, + .instance_size = sizeof(RngBuiltin), + .instance_init = rng_builtin_init, + .instance_finalize = rng_builtin_finalize, + .class_init = rng_builtin_class_init, +}; + +static void register_types(void) +{ + type_register_static(&rng_builtin_info); +} + +type_init(register_types); @@ -4165,7 +4165,6 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, { BdrvChild *c, *next; GSList *list = NULL, *p; - uint64_t old_perm, old_shared; uint64_t perm = 0, shared = BLK_PERM_ALL; int ret; @@ -4211,8 +4210,8 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, bdrv_unref(from); } - bdrv_get_cumulative_perm(to, &old_perm, &old_shared); - bdrv_set_perm(to, old_perm | perm, old_shared | shared); + bdrv_get_cumulative_perm(to, &perm, &shared); + bdrv_set_perm(to, perm, shared); out: g_slist_free(list); diff --git a/block/file-posix.c b/block/file-posix.c index fbeb0068db..87c5a4ccbd 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -380,7 +380,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) for (i = 0; i < ARRAY_SIZE(alignments); i++) { align = alignments[i]; if (raw_is_io_aligned(fd, buf + align, max_align)) { - /* Fallback to request_aligment. */ + /* Fallback to request_alignment. */ s->buf_align = (align != 1) ? align : bs->bl.request_alignment; break; } @@ -1588,6 +1588,13 @@ static int handle_aiocb_write_zeroes(void *opaque) if (s->has_write_zeroes) { int ret = do_fallocate(s->fd, FALLOC_FL_ZERO_RANGE, aiocb->aio_offset, aiocb->aio_nbytes); + if (ret == -EINVAL) { + /* + * Allow falling back to pwrite for file systems that + * do not support fallocate() for an unaligned byte range. + */ + return -ENOTSUP; + } if (ret == 0 || ret != -ENOTSUP) { return ret; } @@ -1749,6 +1756,43 @@ static int handle_aiocb_discard(void *opaque) return ret; } +/* + * Help alignment probing by allocating the first block. + * + * When reading with direct I/O from unallocated area on Gluster backed by XFS, + * reading succeeds regardless of request length. In this case we fallback to + * safe alignment which is not optimal. Allocating the first block avoids this + * fallback. + * + * fd may be opened with O_DIRECT, but we don't know the buffer alignment or + * request alignment, so we use safe values. + * + * Returns: 0 on success, -errno on failure. Since this is an optimization, + * caller may ignore failures. + */ +static int allocate_first_block(int fd, size_t max_size) +{ + size_t write_size = (max_size < MAX_BLOCKSIZE) + ? BDRV_SECTOR_SIZE + : MAX_BLOCKSIZE; + size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize()); + void *buf; + ssize_t n; + int ret; + + buf = qemu_memalign(max_align, write_size); + memset(buf, 0, write_size); + + do { + n = pwrite(fd, buf, write_size, 0); + } while (n == -1 && errno == EINTR); + + ret = (n == -1) ? -errno : 0; + + qemu_vfree(buf); + return ret; +} + static int handle_aiocb_truncate(void *opaque) { RawPosixAIOData *aiocb = opaque; @@ -1788,6 +1832,17 @@ static int handle_aiocb_truncate(void *opaque) /* posix_fallocate() doesn't set errno. */ error_setg_errno(errp, -result, "Could not preallocate new data"); + } else if (current_length == 0) { + /* + * posix_fallocate() uses fallocate() if the filesystem + * supports it, or fallback to manually writing zeroes. If + * fallocate() was used, unaligned reads from the fallocated + * area in raw_probe_alignment() will succeed, hence we need to + * allocate the first block. + * + * Optimize future alignment probing; ignore failures. + */ + allocate_first_block(fd, offset); } } else { result = 0; @@ -1849,6 +1904,9 @@ static int handle_aiocb_truncate(void *opaque) if (ftruncate(fd, offset) != 0) { result = -errno; error_setg_errno(errp, -result, "Could not resize file"); + } else if (current_length == 0 && offset > current_length) { + /* Optimize future alignment probing; ignore failures. */ + allocate_first_block(fd, offset); } return result; default: diff --git a/block/io.c b/block/io.c index 0fa10831ed..16a598fd08 100644 --- a/block/io.c +++ b/block/io.c @@ -1746,7 +1746,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, assert(!bs->supported_zero_flags); } - if (ret < 0 && !(flags & BDRV_REQ_NO_FALLBACK)) { + if (ret == -ENOTSUP && !(flags & BDRV_REQ_NO_FALLBACK)) { /* Fall back to bounce buffer if write zeroes is unsupported */ BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE; diff --git a/block/nbd.c b/block/nbd.c index beed46fb34..813c40d8f0 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1044,6 +1044,10 @@ static int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, if (!(flags & BDRV_REQ_MAY_UNMAP)) { request.flags |= NBD_CMD_FLAG_NO_HOLE; } + if (flags & BDRV_REQ_NO_FALLBACK) { + assert(s->info.flags & NBD_FLAG_SEND_FAST_ZERO); + request.flags |= NBD_CMD_FLAG_FAST_ZERO; + } if (!bytes) { return 0; @@ -1239,6 +1243,9 @@ static int nbd_client_connect(BlockDriverState *bs, Error **errp) } if (s->info.flags & NBD_FLAG_SEND_WRITE_ZEROES) { bs->supported_zero_flags |= BDRV_REQ_MAY_UNMAP; + if (s->info.flags & NBD_FLAG_SEND_FAST_ZERO) { + bs->supported_zero_flags |= BDRV_REQ_NO_FALLBACK; + } } s->sioc = sioc; @@ -1374,7 +1381,7 @@ static bool nbd_has_filename_options_conflict(QDict *options, Error **errp) static void nbd_parse_filename(const char *filename, QDict *options, Error **errp) { - char *file; + g_autofree char *file = NULL; char *export_name; const char *host_spec; const char *unixpath; @@ -1396,7 +1403,7 @@ static void nbd_parse_filename(const char *filename, QDict *options, export_name = strstr(file, EN_OPTSTR); if (export_name) { if (export_name[strlen(EN_OPTSTR)] == 0) { - goto out; + return; } export_name[0] = 0; /* truncate 'file' */ export_name += strlen(EN_OPTSTR); @@ -1407,11 +1414,11 @@ static void nbd_parse_filename(const char *filename, QDict *options, /* extract the host_spec - fail if it's not nbd:... */ if (!strstart(file, "nbd:", &host_spec)) { error_setg(errp, "File name string for NBD must start with 'nbd:'"); - goto out; + return; } if (!*host_spec) { - goto out; + return; } /* are we a UNIX or TCP socket? */ @@ -1431,9 +1438,6 @@ static void nbd_parse_filename(const char *filename, QDict *options, out_inet: qapi_free_InetSocketAddress(addr); } - -out: - g_free(file); } static bool nbd_process_legacy_socket_options(QDict *output_options, diff --git a/block/vmdk.c b/block/vmdk.c index fd78fd0ccf..fed3b50c8a 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1076,8 +1076,7 @@ static const char *next_line(const char *s) } static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, - const char *desc_file_path, QDict *options, - Error **errp) + QDict *options, Error **errp) { int ret; int matches; @@ -1087,6 +1086,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, const char *p, *np; int64_t sectors = 0; int64_t flat_offset; + char *desc_file_dir = NULL; char *extent_path; BdrvChild *extent_file; BDRVVmdkState *s = bs->opaque; @@ -1130,16 +1130,23 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, continue; } - if (!path_is_absolute(fname) && !path_has_protocol(fname) && - !desc_file_path[0]) - { - bdrv_refresh_filename(bs->file->bs); - error_setg(errp, "Cannot use relative extent paths with VMDK " - "descriptor file '%s'", bs->file->bs->filename); - return -EINVAL; - } + if (path_is_absolute(fname)) { + extent_path = g_strdup(fname); + } else { + if (!desc_file_dir) { + desc_file_dir = bdrv_dirname(bs->file->bs, errp); + if (!desc_file_dir) { + bdrv_refresh_filename(bs->file->bs); + error_prepend(errp, "Cannot use relative paths with VMDK " + "descriptor file '%s': ", + bs->file->bs->filename); + ret = -EINVAL; + goto out; + } + } - extent_path = path_combine(desc_file_path, fname); + extent_path = g_strconcat(desc_file_dir, fname, NULL); + } ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents); assert(ret < 32); @@ -1149,7 +1156,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, g_free(extent_path); if (local_err) { error_propagate(errp, local_err); - return -EINVAL; + ret = -EINVAL; + goto out; } /* save to extents array */ @@ -1160,7 +1168,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, 0, 0, 0, 0, 0, &extent, errp); if (ret < 0) { bdrv_unref_child(bs, extent_file); - return ret; + goto out; } extent->flat_start_offset = flat_offset << 9; } else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) { @@ -1175,24 +1183,27 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, g_free(buf); if (ret) { bdrv_unref_child(bs, extent_file); - return ret; + goto out; } extent = &s->extents[s->num_extents - 1]; } else if (!strcmp(type, "SESPARSE")) { ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp); if (ret) { bdrv_unref_child(bs, extent_file); - return ret; + goto out; } extent = &s->extents[s->num_extents - 1]; } else { error_setg(errp, "Unsupported extent type '%s'", type); bdrv_unref_child(bs, extent_file); - return -ENOTSUP; + ret = -ENOTSUP; + goto out; } extent->type = g_strdup(type); } - return 0; + + ret = 0; + goto out; invalid: np = next_line(p); @@ -1201,7 +1212,11 @@ invalid: np--; } error_setg(errp, "Invalid extent line: %.*s", (int)(np - p), p); - return -EINVAL; + ret = -EINVAL; + +out: + g_free(desc_file_dir); + return ret; } static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, @@ -1228,8 +1243,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, } s->create_type = g_strdup(ct); s->desc_offset = 0; - ret = vmdk_parse_extents(buf, bs, bs->file->bs->exact_filename, options, - errp); + ret = vmdk_parse_extents(buf, bs, options, errp); exit: return ret; } @@ -1720,6 +1734,16 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, if (extent->compressed) { void *compressed_data; + /* Only whole clusters */ + if (offset_in_cluster || + n_bytes > (extent->cluster_sectors * SECTOR_SIZE) || + (n_bytes < (extent->cluster_sectors * SECTOR_SIZE) && + offset + n_bytes != extent->end_sector * SECTOR_SIZE)) + { + ret = -EINVAL; + goto out; + } + if (!extent->has_marker) { ret = -EINVAL; goto out; diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 7a71da447f..213f226ac1 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -101,7 +101,7 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds, qio_net_listener_set_name(nbd_server->listener, "nbd-listener"); - if (qio_net_listener_open_sync(nbd_server->listener, addr, errp) < 0) { + if (qio_net_listener_open_sync(nbd_server->listener, addr, 1, errp) < 0) { goto error; } @@ -187,8 +187,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, writable = false; } - exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, - writable ? 0 : NBD_FLAG_READ_ONLY, + exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, !writable, !writable, NULL, false, on_eject_blk, errp); if (!exp) { return; diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 03f03407b0..185fe38dda 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1170,7 +1170,7 @@ static int qmp_chardev_open_socket_server(Chardev *chr, qio_net_listener_set_name(s->listener, name); g_free(name); - if (qio_net_listener_open_sync(s->listener, s->addr, errp) < 0) { + if (qio_net_listener_open_sync(s->listener, s->addr, 1, errp) < 0) { object_unref(OBJECT(s->listener)); s->listener = NULL; return -1; @@ -495,27 +495,10 @@ qed="yes" parallels="yes" sheepdog="yes" libxml2="" -docker="no" debug_mutex="no" libpmem="" default_devices="yes" -# cross compilers defaults, can be overridden with --cross-cc-ARCH -cross_cc_aarch64="aarch64-linux-gnu-gcc" -cross_cc_aarch64_be="$cross_cc_aarch64" -cross_cc_cflags_aarch64_be="-mbig-endian" -cross_cc_arm="arm-linux-gnueabihf-gcc" -cross_cc_cflags_armeb="-mbig-endian" -cross_cc_i386="i386-pc-linux-gnu-gcc" -cross_cc_cflags_i386="" -cross_cc_ppc="powerpc-linux-gnu-gcc" -cross_cc_cflags_ppc="-m32" -cross_cc_ppc64="powerpc-linux-gnu-gcc" -cross_cc_cflags_ppc64="-m64" -cross_cc_ppc64le="powerpc64le-linux-gnu-gcc" - -enabled_cross_compilers="" - supported_cpu="no" supported_os="no" bogus_os="no" @@ -548,9 +531,12 @@ for opt do ;; --cross-cc-cflags-*) cc_arch=${opt#--cross-cc-flags-}; cc_arch=${cc_arch%%=*} eval "cross_cc_cflags_${cc_arch}=\$optarg" + cross_cc_vars="$cross_cc_vars cross_cc_cflags_${cc_arch}" ;; --cross-cc-*) cc_arch=${opt#--cross-cc-}; cc_arch=${cc_arch%%=*} + cc_archs="$cc_archs $cc_arch" eval "cross_cc_${cc_arch}=\$optarg" + cross_cc_vars="$cross_cc_vars cross_cc_${cc_arch}" ;; esac done @@ -745,42 +731,34 @@ ARCH= case "$cpu" in ppc|ppc64|s390|s390x|sparc64|x32|riscv32|riscv64) supported_cpu="yes" - eval "cross_cc_${cpu}=\$host_cc" ;; ppc64le) ARCH="ppc64" supported_cpu="yes" - cross_cc_ppc64le=$host_cc ;; i386|i486|i586|i686|i86pc|BePC) cpu="i386" supported_cpu="yes" - cross_cc_i386=$host_cc ;; x86_64|amd64) cpu="x86_64" supported_cpu="yes" - cross_cc_x86_64=$host_cc ;; armv*b|armv*l|arm) cpu="arm" supported_cpu="yes" - cross_cc_arm=$host_cc ;; aarch64) cpu="aarch64" supported_cpu="yes" - cross_cc_aarch64=$host_cc ;; mips*) cpu="mips" supported_cpu="yes" - cross_cc_mips=$host_cc ;; sparc|sun4[cdmuv]) cpu="sparc" supported_cpu="yes" - cross_cc_sparc=$host_cc ;; *) # This will result in either an error or falling back to TCI later @@ -1555,44 +1533,30 @@ case "$cpu" in ppc) CPU_CFLAGS="-m32" LDFLAGS="-m32 $LDFLAGS" - cross_cc_ppc=$cc - cross_cc_cflags_ppc="$CPU_CFLAGS" ;; ppc64) CPU_CFLAGS="-m64" LDFLAGS="-m64 $LDFLAGS" - cross_cc_ppc64=$cc - cross_cc_cflags_ppc64="$CPU_CFLAGS" ;; sparc) CPU_CFLAGS="-m32 -mv8plus -mcpu=ultrasparc" LDFLAGS="-m32 -mv8plus $LDFLAGS" - cross_cc_sparc=$cc - cross_cc_cflags_sparc="$CPU_CFLAGS" ;; sparc64) CPU_CFLAGS="-m64 -mcpu=ultrasparc" LDFLAGS="-m64 $LDFLAGS" - cross_cc_sparc64=$cc - cross_cc_cflags_sparc64="$CPU_CFLAGS" ;; s390) CPU_CFLAGS="-m31" LDFLAGS="-m31 $LDFLAGS" - cross_cc_s390=$cc - cross_cc_cflags_s390="$CPU_CFLAGS" ;; s390x) CPU_CFLAGS="-m64" LDFLAGS="-m64 $LDFLAGS" - cross_cc_s390x=$cc - cross_cc_cflags_s390x="$CPU_CFLAGS" ;; i386) CPU_CFLAGS="-m32" LDFLAGS="-m32 $LDFLAGS" - cross_cc_i386=$cc - cross_cc_cflags_i386="$CPU_CFLAGS" ;; x86_64) # ??? Only extremely old AMD cpus do not have cmpxchg16b. @@ -1600,18 +1564,16 @@ case "$cpu" in # runtime and generate the fallback to serial emulation. CPU_CFLAGS="-m64 -mcx16" LDFLAGS="-m64 $LDFLAGS" - cross_cc_x86_64=$cc - cross_cc_cflags_x86_64="$CPU_CFLAGS" ;; x32) CPU_CFLAGS="-mx32" LDFLAGS="-mx32 $LDFLAGS" - cross_cc_i386=$cc - cross_cc_cflags_i386="$CPU_CFLAGS" ;; # No special flags required for other host CPUs esac +eval "cross_cc_${cpu}=\$host_cc" +cross_cc_vars="$cross_cc_vars cross_cc_${cpu}" QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS" # For user-mode emulation the host arch has to be one we explicitly @@ -1864,7 +1826,7 @@ if ! $python -c 'import sys; sys.exit(sys.version_info < (2,7))'; then fi # Preserve python version since some functionality is dependent on it -python_version=$($python -V 2>&1 | sed -e 's/Python\ //') +python_version=$($python -c 'import sys; print("%d.%d.%d" % (sys.version_info[0], sys.version_info[1], sys.version_info[2]))' 2>/dev/null) # Suppress writing compiled files python="$python -B" @@ -2059,6 +2021,12 @@ static THREAD int tls_var; int main(void) { return tls_var; } EOF + # check we support --no-pie first... + if compile_prog "-Werror -fno-pie" "-no-pie"; then + CFLAGS_NOPIE="-fno-pie" + LDFLAGS_NOPIE="-nopie" + fi + if compile_prog "-fPIE -DPIE" "-pie"; then QEMU_CFLAGS="-fPIE -DPIE $QEMU_CFLAGS" LDFLAGS="-pie $LDFLAGS" @@ -2074,11 +2042,6 @@ EOF pie="no" fi fi - - if compile_prog "-Werror -fno-pie" "-nopie"; then - CFLAGS_NOPIE="-fno-pie" - LDFLAGS_NOPIE="-nopie" - fi fi ########################################## @@ -5894,17 +5857,6 @@ EOF fi ########################################## -# Docker and cross-compiler support -# -# This is specifically for building test -# cases for foreign architectures, not -# cross-compiling QEMU itself. - -if has "docker"; then - docker=$($python $source_path/tests/docker/docker.py probe) -fi - -########################################## # check for libpmem if test "$libpmem" != "no"; then @@ -6474,7 +6426,6 @@ echo "qed support $qed" echo "parallels support $parallels" echo "sheepdog support $sheepdog" echo "capstone $capstone" -echo "docker $docker" echo "libpmem support $libpmem" echo "libudev $libudev" echo "default devices $default_devices" @@ -6511,6 +6462,7 @@ if ! $python -c 'import sys; sys.exit(sys.version_info < (3,0))'; then echo echo "warning: Python 2 support is deprecated" >&2 echo "warning: Python 3 will be required for building future versions of QEMU" >&2 + python2="y" fi config_host_mak="config-host.mak" @@ -7333,7 +7285,7 @@ echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak echo "INSTALL_LIB=$install -c -m 0644" >> $config_host_mak echo "PYTHON=$python" >> $config_host_mak -echo "PYTHON_VERSION=$python_version" >> $config_host_mak +echo "PYTHON2=$python2" >> $config_host_mak echo "CC=$cc" >> $config_host_mak if $iasl -h > /dev/null 2>&1; then echo "IASL=$iasl" >> $config_host_mak @@ -7383,10 +7335,6 @@ if test "$gcov" = "yes" ; then echo "GCOV=$gcov_tool" >> $config_host_mak fi -if test "$docker" != "no"; then - echo "HAVE_USER_DOCKER=y" >> $config_host_mak -fi - if test "$libudev" != "no"; then echo "CONFIG_LIBUDEV=y" >> $config_host_mak echo "LIBUDEV_LIBS=$libudev_libs" >> $config_host_mak @@ -7460,10 +7408,6 @@ case "$target" in ;; esac -target_compiler="" -target_compiler_static="" -target_compiler_cflags="" - mkdir -p $target_dir echo "# Automatically generated by configure - do not modify" > $config_target_mak @@ -7480,26 +7424,20 @@ case "$target_name" in i386) mttcg="yes" gdb_xml_files="i386-32bit.xml" - target_compiler=$cross_cc_i386 - target_compiler_cflags=$cross_cc_ccflags_i386 ;; x86_64) TARGET_BASE_ARCH=i386 mttcg="yes" gdb_xml_files="i386-64bit.xml" - target_compiler=$cross_cc_x86_64 ;; alpha) mttcg="yes" - target_compiler=$cross_cc_alpha ;; arm|armeb) TARGET_ARCH=arm bflt="yes" mttcg="yes" gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" - target_compiler=$cross_cc_arm - eval "target_compiler_cflags=\$cross_cc_cflags_${target_name}" ;; aarch64|aarch64_be) TARGET_ARCH=aarch64 @@ -7507,41 +7445,32 @@ case "$target_name" in bflt="yes" mttcg="yes" gdb_xml_files="aarch64-core.xml aarch64-fpu.xml arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" - target_compiler=$cross_cc_aarch64 - eval "target_compiler_cflags=\$cross_cc_cflags_${target_name}" ;; cris) - target_compiler=$cross_cc_cris ;; hppa) mttcg="yes" - target_compiler=$cross_cc_hppa ;; lm32) - target_compiler=$cross_cc_lm32 ;; m68k) bflt="yes" gdb_xml_files="cf-core.xml cf-fp.xml m68k-fp.xml" - target_compiler=$cross_cc_m68k ;; microblaze|microblazeel) TARGET_ARCH=microblaze bflt="yes" echo "TARGET_ABI32=y" >> $config_target_mak - target_compiler=$cross_cc_microblaze ;; mips|mipsel) mttcg="yes" TARGET_ARCH=mips - target_compiler=$cross_cc_mips echo "TARGET_ABI_MIPSO32=y" >> $config_target_mak ;; mipsn32|mipsn32el) mttcg="yes" TARGET_ARCH=mips64 TARGET_BASE_ARCH=mips - target_compiler=$cross_cc_mipsn32 echo "TARGET_ABI_MIPSN32=y" >> $config_target_mak echo "TARGET_ABI32=y" >> $config_target_mak ;; @@ -7549,32 +7478,24 @@ case "$target_name" in mttcg="yes" TARGET_ARCH=mips64 TARGET_BASE_ARCH=mips - target_compiler=$cross_cc_mips64 echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak ;; moxie) - target_compiler=$cross_cc_moxie ;; nios2) - target_compiler=$cross_cc_nios2 ;; or1k) - target_compiler=$cross_cc_or1k TARGET_ARCH=openrisc TARGET_BASE_ARCH=openrisc ;; ppc) gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" - target_compiler=$cross_cc_ppc - target_compiler_cflags="$cross_cc_cflags_ppc" ;; ppc64) TARGET_BASE_ARCH=ppc TARGET_ABI_DIR=ppc mttcg=yes gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml" - target_compiler=$cross_cc_ppc64 - target_compiler_cflags="$cross_cc_cflags_ppc64" ;; ppc64le) TARGET_ARCH=ppc64 @@ -7582,7 +7503,6 @@ case "$target_name" in TARGET_ABI_DIR=ppc mttcg=yes gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml" - target_compiler=$cross_cc_ppc64le ;; ppc64abi32) TARGET_ARCH=ppc64 @@ -7590,60 +7510,48 @@ case "$target_name" in TARGET_ABI_DIR=ppc echo "TARGET_ABI32=y" >> $config_target_mak gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml" - target_compiler=$cross_cc_ppc64abi32 ;; riscv32) TARGET_BASE_ARCH=riscv TARGET_ABI_DIR=riscv mttcg=yes gdb_xml_files="riscv-32bit-cpu.xml riscv-32bit-fpu.xml riscv-32bit-csr.xml" - target_compiler=$cross_cc_riscv32 ;; riscv64) TARGET_BASE_ARCH=riscv TARGET_ABI_DIR=riscv mttcg=yes gdb_xml_files="riscv-64bit-cpu.xml riscv-64bit-fpu.xml riscv-64bit-csr.xml" - target_compiler=$cross_cc_riscv64 ;; sh4|sh4eb) TARGET_ARCH=sh4 bflt="yes" - target_compiler=$cross_cc_sh4 ;; sparc) - target_compiler=$cross_cc_sparc ;; sparc64) TARGET_BASE_ARCH=sparc - target_compiler=$cross_cc_sparc64 ;; sparc32plus) TARGET_ARCH=sparc64 TARGET_BASE_ARCH=sparc TARGET_ABI_DIR=sparc - target_compiler=$cross_cc_sparc32plus echo "TARGET_ABI32=y" >> $config_target_mak ;; s390x) mttcg=yes gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml s390-cr.xml s390-virt.xml s390-gs.xml" - target_compiler=$cross_cc_s390x ;; tilegx) - target_compiler=$cross_cc_tilegx ;; tricore) - target_compiler=$cross_cc_tricore ;; unicore32) - target_compiler=$cross_cc_unicore32 ;; xtensa|xtensaeb) TARGET_ARCH=xtensa bflt="yes" mttcg="yes" - target_compiler=$cross_cc_xtensa ;; *) error_exit "Unsupported target CPU" @@ -7654,27 +7562,6 @@ if [ "$TARGET_BASE_ARCH" = "" ]; then TARGET_BASE_ARCH=$TARGET_ARCH fi -# Do we have a cross compiler for this target? -if has $target_compiler; then - - write_c_skeleton - - if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC -static ; then - # For host systems we might get away with building without -static - if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC ; then - target_compiler="" - else - enabled_cross_compilers="${enabled_cross_compilers} '${target_compiler}'" - target_compiler_static="n" - fi - else - enabled_cross_compilers="${enabled_cross_compilers} '${target_compiler}'" - target_compiler_static="y" - fi -else - target_compiler="" -fi - symlink "$source_path/Makefile.target" "$target_dir/Makefile" upper() { @@ -7751,18 +7638,6 @@ if test "$target_bsd_user" = "yes" ; then echo "CONFIG_BSD_USER=y" >> $config_target_mak fi -if test -n "$target_compiler"; then - echo "CROSS_CC_GUEST=\"$target_compiler\"" >> $config_target_mak - - if test -n "$target_compiler_static"; then - echo "CROSS_CC_GUEST_STATIC=$target_compiler_static" >> $config_target_mak - fi - - if test -n "$target_compiler_cflags"; then - echo "CROSS_CC_GUEST_CFLAGS=$target_compiler_cflags" >> $config_target_mak - fi -fi - # generate QEMU_CFLAGS/LDFLAGS for targets @@ -7893,11 +7768,6 @@ done # for target in $targets echo "PIXMAN_CFLAGS=$pixman_cflags" >> $config_host_mak echo "PIXMAN_LIBS=$pixman_libs" >> $config_host_mak -if test -n "$enabled_cross_compilers"; then - echo - echo "NOTE: cross-compilers enabled: $enabled_cross_compilers" -fi - if [ "$fdt" = "git" ]; then echo "config-host.h: dtc/all" >> $config_host_mak fi @@ -7926,15 +7796,14 @@ fi # so the build tree will be missing the link back to the new file, and # tests might fail. Prefer to keep the relevant files in their own # directory and symlink the directory instead. -DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm" +DIRS="tests tests/tcg tests/tcg/lm32 tests/libqos tests/qapi-schema tests/qemu-iotests tests/vm" DIRS="$DIRS tests/fp tests/qgraph" DIRS="$DIRS docs docs/interop fsdev scsi" DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw" DIRS="$DIRS roms/seabios roms/vgabios" -LINKS="Makefile tests/tcg/Makefile" -LINKS="$LINKS tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit" -LINKS="$LINKS tests/tcg/lm32/Makefile tests/tcg/xtensa/Makefile po/Makefile" -LINKS="$LINKS tests/fp/Makefile" +LINKS="Makefile" +LINKS="$LINKS tests/tcg/lm32/Makefile po/Makefile" +LINKS="$LINKS tests/tcg/Makefile.target tests/fp/Makefile" LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps" LINKS="$LINKS pc-bios/spapr-rtas/Makefile" LINKS="$LINKS pc-bios/s390-ccw/Makefile" @@ -7964,6 +7833,12 @@ for f in $LINKS ; do fi done +(for i in $cross_cc_vars; do + export $i +done +export target_list source_path +$source_path/tests/tcg/configure.sh) + # temporary config to build submodules for rom in seabios vgabios ; do config_mak=roms/$rom/config.mak diff --git a/contrib/gitdm/aliases b/contrib/gitdm/aliases index 07fd3391a5..c1e744312f 100644 --- a/contrib/gitdm/aliases +++ b/contrib/gitdm/aliases @@ -1,6 +1,22 @@ # -# This is the email aliases file, mapping secondary addresses -# onto a single, canonical address. Duplicates some info from .mailmap +# This is the email aliases file, mapping secondary addresses onto a +# single, canonical address. It duplicates some info from .mailmap so +# if you are adding something here also consider if the .mailmap needs +# updating. +# +# If you just want to avoid gitdm complaining about author fields +# which are actually email addresses with the message: +# +# "...is an author name, probably not what you want" +# +# you can just apply --use-mailmap to you git-log command, e.g: +# +# git log --use-mailmap --numstat --since "last 2 years" | $GITDM +# +# however that will have the effect of squashing multiple addresses to +# a canonical address which will distort the stats of those who +# contribute in both personal and professional capacities from +# different addresses. # # weird commits diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map index fa9d454473..9efe066ec9 100644 --- a/contrib/gitdm/domain-map +++ b/contrib/gitdm/domain-map @@ -18,6 +18,7 @@ nokia.com Nokia oracle.com Oracle proxmox.com Proxmox redhat.com Red Hat +rt-rk.com RT-RK siemens.com Siemens sifive.com SiFive suse.de SUSE diff --git a/contrib/gitdm/filetypes.txt b/contrib/gitdm/filetypes.txt index 165b71b3f9..2d5002fea0 100644 --- a/contrib/gitdm/filetypes.txt +++ b/contrib/gitdm/filetypes.txt @@ -34,7 +34,7 @@ # If there is an filetype which is not in order but has values, it will # be added at the end. # -order build,tests,code,documentation,devel-doc,blobs +order build,interface,tests,code,documentation,devel-doc,blobs # # diff --git a/contrib/gitdm/group-map-individuals b/contrib/gitdm/group-map-individuals index 05e355d30e..1c84717438 100644 --- a/contrib/gitdm/group-map-individuals +++ b/contrib/gitdm/group-map-individuals @@ -2,7 +2,8 @@ # Individual and personal contributors # # This is simply to allow prolific developers with no company -# affiliations to be grouped together in the summary stats. +# affiliations (or non-company related personal work) to be grouped +# together in the summary stats. # f4bug@amsat.org diff --git a/contrib/gitdm/group-map-redhat b/contrib/gitdm/group-map-redhat index 6d05c6b54f..d15db2d35e 100644 --- a/contrib/gitdm/group-map-redhat +++ b/contrib/gitdm/group-map-redhat @@ -5,3 +5,4 @@ david@gibson.dropbear.id.au laurent@vivier.eu pjp@fedoraproject.org +armbru@pond.sub.org diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index 4b36e35a82..68c27136ae 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -94,6 +94,11 @@ bool vu_has_feature(VuDev *dev, return has_feature(dev->features, fbit); } +static inline bool vu_has_protocol_feature(VuDev *dev, unsigned int fbit) +{ + return has_feature(dev->protocol_features, fbit); +} + static const char * vu_request_to_string(unsigned int req) { @@ -951,8 +956,7 @@ vu_check_queue_inflights(VuDev *dev, VuVirtq *vq) { int i = 0; - if (!has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) { + if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) { return 0; } @@ -1097,7 +1101,7 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, vmsg.fd_num = fd_num; - if ((dev->protocol_features & VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD) == 0) { + if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD)) { return false; } @@ -2190,8 +2194,7 @@ vu_queue_map_desc(VuDev *dev, VuVirtq *vq, unsigned int idx, size_t sz) static int vu_queue_inflight_get(VuDev *dev, VuVirtq *vq, int desc_idx) { - if (!has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) { + if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) { return 0; } @@ -2208,8 +2211,7 @@ vu_queue_inflight_get(VuDev *dev, VuVirtq *vq, int desc_idx) static int vu_queue_inflight_pre_put(VuDev *dev, VuVirtq *vq, int desc_idx) { - if (!has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) { + if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) { return 0; } @@ -2225,8 +2227,7 @@ vu_queue_inflight_pre_put(VuDev *dev, VuVirtq *vq, int desc_idx) static int vu_queue_inflight_post_put(VuDev *dev, VuVirtq *vq, int desc_idx) { - if (!has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) { + if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) { return 0; } diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak index 4049a8f2ba..d67ab8b96d 100644 --- a/default-configs/m68k-softmmu.mak +++ b/default-configs/m68k-softmmu.mak @@ -6,3 +6,4 @@ CONFIG_SEMIHOSTING=y # CONFIG_AN5206=y CONFIG_MCF5208=y +CONFIG_NEXTCUBE=y diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt index fc64473e02..4511880961 100644 --- a/docs/interop/nbd.txt +++ b/docs/interop/nbd.txt @@ -53,3 +53,5 @@ the operation of that feature. * 2.12: NBD_CMD_BLOCK_STATUS for "base:allocation" * 3.0: NBD_OPT_STARTTLS with TLS Pre-Shared Keys (PSK), NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE +* 4.2: NBD_FLAG_CAN_MULTI_CONN for sharable read-only exports, +NBD_CMD_FLAG_FAST_ZERO diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi index c02547e28c..2c7ea49c32 100644 --- a/docs/qemu-block-drivers.texi +++ b/docs/qemu-block-drivers.texi @@ -2,6 +2,8 @@ QEMU block driver reference manual @c man end +@set qemu_system qemu-system-x86_64 + @c man begin DESCRIPTION @node disk_images_formats @@ -405,7 +407,7 @@ QEMU can automatically create a virtual FAT disk image from a directory tree. In order to use it, just type: @example -qemu-system-i386 linux.img -hdb fat:/my_directory +@value{qemu_system} linux.img -hdb fat:/my_directory @end example Then you access access to all the files in the @file{/my_directory} @@ -415,14 +417,14 @@ them via SAMBA or NFS. The default access is @emph{read-only}. Floppies can be emulated with the @code{:floppy:} option: @example -qemu-system-i386 linux.img -fda fat:floppy:/my_directory +@value{qemu_system} linux.img -fda fat:floppy:/my_directory @end example A read/write support is available for testing (beta stage) with the @code{:rw:} option: @example -qemu-system-i386 linux.img -fda fat:floppy:rw:/my_directory +@value{qemu_system} linux.img -fda fat:floppy:rw:/my_directory @end example What you should @emph{never} do: @@ -440,14 +442,14 @@ QEMU can access directly to block device exported using the Network Block Device protocol. @example -qemu-system-i386 linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/ +@value{qemu_system} linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/ @end example If the NBD server is located on the same host, you can use an unix socket instead of an inet socket: @example -qemu-system-i386 linux.img -hdb nbd+unix://?socket=/tmp/my_socket +@value{qemu_system} linux.img -hdb nbd+unix://?socket=/tmp/my_socket @end example In this case, the block device must be exported using qemu-nbd: @@ -464,23 +466,23 @@ qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2 @noindent and then you can use it with two guests: @example -qemu-system-i386 linux1.img -hdb nbd+unix://?socket=/tmp/my_socket -qemu-system-i386 linux2.img -hdb nbd+unix://?socket=/tmp/my_socket +@value{qemu_system} linux1.img -hdb nbd+unix://?socket=/tmp/my_socket +@value{qemu_system} linux2.img -hdb nbd+unix://?socket=/tmp/my_socket @end example If the nbd-server uses named exports (supported since NBD 2.9.18, or with QEMU's own embedded NBD server), you must specify an export name in the URI: @example -qemu-system-i386 -cdrom nbd://localhost/debian-500-ppc-netinst -qemu-system-i386 -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst +@value{qemu_system} -cdrom nbd://localhost/debian-500-ppc-netinst +@value{qemu_system} -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst @end example The URI syntax for NBD is supported since QEMU 1.3. An alternative syntax is also available. Here are some example of the older syntax: @example -qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024 -qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket -qemu-system-i386 -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst +@value{qemu_system} linux.img -hdb nbd:my_nbd_server.mydomain.org:1024 +@value{qemu_system} linux2.img -hdb nbd:unix:/tmp/my_socket +@value{qemu_system} -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst @end example @node disk_images_sheepdog @@ -505,7 +507,7 @@ qemu-img convert @var{filename} sheepdog:///@var{image} You can boot from the Sheepdog disk image with the command: @example -qemu-system-i386 sheepdog:///@var{image} +@value{qemu_system} sheepdog:///@var{image} @end example You can also create a snapshot of the Sheepdog image like qcow2. @@ -517,7 +519,7 @@ where @var{tag} is a tag name of the newly created snapshot. To boot from the Sheepdog snapshot, specify the tag name of the snapshot. @example -qemu-system-i386 sheepdog:///@var{image}#@var{tag} +@value{qemu_system} sheepdog:///@var{image}#@var{tag} @end example You can create a cloned image from the existing snapshot. @@ -530,14 +532,14 @@ is its tag name. You can use an unix socket instead of an inet socket: @example -qemu-system-i386 sheepdog+unix:///@var{image}?socket=@var{path} +@value{qemu_system} sheepdog+unix:///@var{image}?socket=@var{path} @end example If the Sheepdog daemon doesn't run on the local host, you need to specify one of the Sheepdog servers to connect to. @example qemu-img create sheepdog://@var{hostname}:@var{port}/@var{image} @var{size} -qemu-system-i386 sheepdog://@var{hostname}:@var{port}/@var{image} +@value{qemu_system} sheepdog://@var{hostname}:@var{port}/@var{image} @end example @node disk_images_iscsi @@ -627,7 +629,7 @@ cat >iscsi.conf <<EOF header-digest = "CRC32C" EOF -qemu-system-i386 -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \ +@value{qemu_system} -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \ -readconfig iscsi.conf @end example @@ -646,7 +648,7 @@ tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 2 \ -b /IMAGES/cd.iso --device-type=cd tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL -qemu-system-i386 -iscsi initiator-name=iqn.qemu.test:my-initiator \ +@value{qemu_system} -iscsi initiator-name=iqn.qemu.test:my-initiator \ -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \ -cdrom iscsi://127.0.0.1/iqn.qemu.test/2 @end example @@ -659,11 +661,11 @@ GlusterFS is a user space distributed file system. You can boot from the GlusterFS disk image with the command: @example URI: -qemu-system-x86_64 -drive file=gluster[+@var{type}]://[@var{host}[:@var{port}]]/@var{volume}/@var{path} +@value{qemu_system} -drive file=gluster[+@var{type}]://[@var{host}[:@var{port}]]/@var{volume}/@var{path} [?socket=...][,file.debug=9][,file.logfile=...] JSON: -qemu-system-x86_64 'json:@{"driver":"qcow2", +@value{qemu_system} 'json:@{"driver":"qcow2", "file":@{"driver":"gluster", "volume":"testvol","path":"a.img","debug":9,"logfile":"...", "server":[@{"type":"tcp","host":"...","port":"..."@}, @@ -711,22 +713,22 @@ qemu-img create gluster://@var{host}/@var{volume}/@var{path} @var{size} Examples @example -qemu-system-x86_64 -drive file=gluster://1.2.3.4/testvol/a.img -qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4/testvol/a.img -qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img -qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img -qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img -qemu-system-x86_64 -drive file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img -qemu-system-x86_64 -drive file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket -qemu-system-x86_64 -drive file=gluster+rdma://1.2.3.4:24007/testvol/a.img -qemu-system-x86_64 -drive file=gluster://1.2.3.4/testvol/a.img,file.debug=9,file.logfile=/var/log/qemu-gluster.log -qemu-system-x86_64 'json:@{"driver":"qcow2", +@value{qemu_system} -drive file=gluster://1.2.3.4/testvol/a.img +@value{qemu_system} -drive file=gluster+tcp://1.2.3.4/testvol/a.img +@value{qemu_system} -drive file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img +@value{qemu_system} -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img +@value{qemu_system} -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img +@value{qemu_system} -drive file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img +@value{qemu_system} -drive file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket +@value{qemu_system} -drive file=gluster+rdma://1.2.3.4:24007/testvol/a.img +@value{qemu_system} -drive file=gluster://1.2.3.4/testvol/a.img,file.debug=9,file.logfile=/var/log/qemu-gluster.log +@value{qemu_system} 'json:@{"driver":"qcow2", "file":@{"driver":"gluster", "volume":"testvol","path":"a.img", "debug":9,"logfile":"/var/log/qemu-gluster.log", "server":[@{"type":"tcp","host":"1.2.3.4","port":24007@}, @{"type":"unix","socket":"/var/run/glusterd.socket"@}]@}@}' -qemu-system-x86_64 -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img, +@value{qemu_system} -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img, file.debug=9,file.logfile=/var/log/qemu-gluster.log, file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007, file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket @@ -739,13 +741,13 @@ You can access disk images located on a remote ssh server by using the ssh protocol: @example -qemu-system-x86_64 -drive file=ssh://[@var{user}@@]@var{server}[:@var{port}]/@var{path}[?host_key_check=@var{host_key_check}] +@value{qemu_system} -drive file=ssh://[@var{user}@@]@var{server}[:@var{port}]/@var{path}[?host_key_check=@var{host_key_check}] @end example Alternative syntax using properties: @example -qemu-system-x86_64 -drive file.driver=ssh[,file.user=@var{user}],file.host=@var{server}[,file.port=@var{port}],file.path=@var{path}[,file.host_key_check=@var{host_key_check}] +@value{qemu_system} -drive file.driver=ssh[,file.user=@var{user}],file.host=@var{server}[,file.port=@var{port}],file.path=@var{path}[,file.host_key_check=@var{host_key_check}] @end example @var{ssh} is the protocol. @@ -808,13 +810,13 @@ driver. For example: # echo 0000:06:0d.0 > /sys/bus/pci/devices/0000:06:0d.0/driver/unbind # echo 1102 0002 > /sys/bus/pci/drivers/vfio-pci/new_id -# qemu-system-x86_64 -drive file=nvme://@var{host}:@var{bus}:@var{slot}.@var{func}/@var{namespace} +# @value{qemu_system} -drive file=nvme://@var{host}:@var{bus}:@var{slot}.@var{func}/@var{namespace} @end example Alternative syntax using properties: @example -qemu-system-x86_64 -drive file.driver=nvme,file.device=@var{host}:@var{bus}:@var{slot}.@var{func},file.namespace=@var{namespace} +@value{qemu_system} -drive file.driver=nvme,file.device=@var{host}:@var{bus}:@var{slot}.@var{func},file.namespace=@var{namespace} @end example @var{host}:@var{bus}:@var{slot}.@var{func} is the NVMe controller's PCI device diff --git a/docs/qemu-cpu-models.texi b/docs/qemu-cpu-models.texi index ad040cfc98..f88a1def0d 100644 --- a/docs/qemu-cpu-models.texi +++ b/docs/qemu-cpu-models.texi @@ -2,6 +2,8 @@ QEMU / KVM CPU model configuration @c man end +@set qemu_system_x86 qemu-system-x86_64 + @c man begin DESCRIPTION @menu @@ -578,25 +580,25 @@ CPU models / features in QEMU and libvirt @item Host passthrough @example - $ qemu-system-x86_64 -cpu host + $ @value{qemu_system_x86} -cpu host @end example With feature customization: @example - $ qemu-system-x86_64 -cpu host,-vmx,... + $ @value{qemu_system_x86} -cpu host,-vmx,... @end example @item Named CPU models @example - $ qemu-system-x86_64 -cpu Westmere + $ @value{qemu_system_x86} -cpu Westmere @end example With feature customization: @example - $ qemu-system-x86_64 -cpu Westmere,+pcid,... + $ @value{qemu_system_x86} -cpu Westmere,+pcid,... @end example @end table @@ -193,15 +193,12 @@ typedef struct subpage_t { #define PHYS_SECTION_UNASSIGNED 0 #define PHYS_SECTION_NOTDIRTY 1 #define PHYS_SECTION_ROM 2 -#define PHYS_SECTION_WATCH 3 static void io_mem_init(void); static void memory_map_init(void); static void tcg_log_global_after_sync(MemoryListener *listener); static void tcg_commit(MemoryListener *listener); -static MemoryRegion io_mem_watch; - /** * CPUAddressSpace: all the information a CPU needs about an AddressSpace * @cpu: the CPU whose AddressSpace this is @@ -1062,28 +1059,7 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc) } #endif -#if defined(CONFIG_USER_ONLY) -void cpu_watchpoint_remove_all(CPUState *cpu, int mask) - -{ -} - -int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len, - int flags) -{ - return -ENOSYS; -} - -void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint) -{ -} - -int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len, - int flags, CPUWatchpoint **watchpoint) -{ - return -ENOSYS; -} -#else +#ifndef CONFIG_USER_ONLY /* Add a watchpoint. */ int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len, int flags, CPUWatchpoint **watchpoint) @@ -1159,9 +1135,8 @@ void cpu_watchpoint_remove_all(CPUState *cpu, int mask) * partially or completely with the address range covered by the * access). */ -static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp, - vaddr addr, - vaddr len) +static inline bool watchpoint_address_matches(CPUWatchpoint *wp, + vaddr addr, vaddr len) { /* We know the lengths are non-zero, but a little caution is * required to avoid errors in the case where the range ends @@ -1174,7 +1149,20 @@ static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp, return !(addr > wpend || wp->vaddr > addrend); } -#endif +/* Return flags for watchpoints that match addr + prot. */ +int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len) +{ + CPUWatchpoint *wp; + int ret = 0; + + QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) { + if (watchpoint_address_matches(wp, addr, TARGET_PAGE_SIZE)) { + ret |= wp->flags; + } + } + return ret; +} +#endif /* !CONFIG_USER_ONLY */ /* Add a breakpoint. */ int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags, @@ -1481,7 +1469,6 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu, target_ulong *address) { hwaddr iotlb; - CPUWatchpoint *wp; if (memory_region_is_ram(section->mr)) { /* Normal RAM. */ @@ -1499,19 +1486,6 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu, iotlb += xlat; } - /* Make accesses to pages with watchpoints go via the - watchpoint trap routines. */ - QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) { - if (cpu_watchpoint_address_matches(wp, vaddr, TARGET_PAGE_SIZE)) { - /* Avoid trapping reads of pages with a write breakpoint. */ - if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) { - iotlb = PHYS_SECTION_WATCH + paddr; - *address |= TLB_MMIO; - break; - } - } - } - return iotlb; } #endif /* defined(CONFIG_USER_ONLY) */ @@ -1750,6 +1724,7 @@ long qemu_minrampagesize(void) long hpsize = LONG_MAX; long mainrampagesize; Object *memdev_root; + MachineState *ms = MACHINE(qdev_get_machine()); mainrampagesize = qemu_mempath_getpagesize(mem_path); @@ -1777,7 +1752,9 @@ long qemu_minrampagesize(void) * so if its page size is smaller we have got to report that size instead. */ if (hpsize > mainrampagesize && - (nb_numa_nodes == 0 || numa_info[0].node_memdev == NULL)) { + (ms->numa_state == NULL || + ms->numa_state->num_nodes == 0 || + ms->numa_state->nodes[0].node_memdev == NULL)) { static bool warned; if (!warned) { error_report("Huge page support disabled (n/a for main memory)."); @@ -2811,32 +2788,35 @@ static const MemoryRegionOps notdirty_mem_ops = { }; /* Generate a debug exception if a watchpoint has been hit. */ -static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags) +void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, + MemTxAttrs attrs, int flags, uintptr_t ra) { - CPUState *cpu = current_cpu; CPUClass *cc = CPU_GET_CLASS(cpu); - target_ulong vaddr; CPUWatchpoint *wp; assert(tcg_enabled()); if (cpu->watchpoint_hit) { - /* We re-entered the check after replacing the TB. Now raise - * the debug interrupt so that is will trigger after the - * current instruction. */ + /* + * We re-entered the check after replacing the TB. + * Now raise the debug interrupt so that it will + * trigger after the current instruction. + */ + qemu_mutex_lock_iothread(); cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG); + qemu_mutex_unlock_iothread(); return; } - vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset; - vaddr = cc->adjust_watchpoint_address(cpu, vaddr, len); + + addr = cc->adjust_watchpoint_address(cpu, addr, len); QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) { - if (cpu_watchpoint_address_matches(wp, vaddr, len) + if (watchpoint_address_matches(wp, addr, len) && (wp->flags & flags)) { if (flags == BP_MEM_READ) { wp->flags |= BP_WATCHPOINT_HIT_READ; } else { wp->flags |= BP_WATCHPOINT_HIT_WRITE; } - wp->hitaddr = vaddr; + wp->hitaddr = MAX(addr, wp->vaddr); wp->hitattrs = attrs; if (!cpu->watchpoint_hit) { if (wp->flags & BP_CPU && @@ -2851,11 +2831,14 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags) if (wp->flags & BP_STOP_BEFORE_ACCESS) { cpu->exception_index = EXCP_DEBUG; mmap_unlock(); - cpu_loop_exit(cpu); + cpu_loop_exit_restore(cpu, ra); } else { /* Force execution of one insn next time. */ cpu->cflags_next_tb = 1 | curr_cflags(); mmap_unlock(); + if (ra) { + cpu_restore_state(cpu, ra, true); + } cpu_loop_exit_noexc(cpu); } } @@ -2865,80 +2848,6 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags) } } -/* Watchpoint access routines. Watchpoints are inserted using TLB tricks, - so these check for a hit then pass through to the normal out-of-line - phys routines. */ -static MemTxResult watch_mem_read(void *opaque, hwaddr addr, uint64_t *pdata, - unsigned size, MemTxAttrs attrs) -{ - MemTxResult res; - uint64_t data; - int asidx = cpu_asidx_from_attrs(current_cpu, attrs); - AddressSpace *as = current_cpu->cpu_ases[asidx].as; - - check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_READ); - switch (size) { - case 1: - data = address_space_ldub(as, addr, attrs, &res); - break; - case 2: - data = address_space_lduw(as, addr, attrs, &res); - break; - case 4: - data = address_space_ldl(as, addr, attrs, &res); - break; - case 8: - data = address_space_ldq(as, addr, attrs, &res); - break; - default: abort(); - } - *pdata = data; - return res; -} - -static MemTxResult watch_mem_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size, - MemTxAttrs attrs) -{ - MemTxResult res; - int asidx = cpu_asidx_from_attrs(current_cpu, attrs); - AddressSpace *as = current_cpu->cpu_ases[asidx].as; - - check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_WRITE); - switch (size) { - case 1: - address_space_stb(as, addr, val, attrs, &res); - break; - case 2: - address_space_stw(as, addr, val, attrs, &res); - break; - case 4: - address_space_stl(as, addr, val, attrs, &res); - break; - case 8: - address_space_stq(as, addr, val, attrs, &res); - break; - default: abort(); - } - return res; -} - -static const MemoryRegionOps watch_mem_ops = { - .read_with_attrs = watch_mem_read, - .write_with_attrs = watch_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 8, - .unaligned = false, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 8, - .unaligned = false, - }, -}; - static MemTxResult flatview_read(FlatView *fv, hwaddr addr, MemTxAttrs attrs, uint8_t *buf, hwaddr len); static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, @@ -3114,9 +3023,6 @@ static void io_mem_init(void) memory_region_init_io(&io_mem_notdirty, NULL, ¬dirty_mem_ops, NULL, NULL, UINT64_MAX); memory_region_clear_global_locking(&io_mem_notdirty); - - memory_region_init_io(&io_mem_watch, NULL, &watch_mem_ops, NULL, - NULL, UINT64_MAX); } AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv) @@ -3130,8 +3036,6 @@ AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv) assert(n == PHYS_SECTION_NOTDIRTY); n = dummy_section(&d->map, fv, &io_mem_rom); assert(n == PHYS_SECTION_ROM); - n = dummy_section(&d->map, fv, &io_mem_watch); - assert(n == PHYS_SECTION_WATCH); d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 }; @@ -3363,8 +3267,9 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr, l = memory_access_size(mr, l, addr1); /* XXX: could force current_cpu to NULL to avoid potential bugs */ - val = ldn_p(buf, l); - result |= memory_region_dispatch_write(mr, addr1, val, l, attrs); + val = ldn_he_p(buf, l); + result |= memory_region_dispatch_write(mr, addr1, val, + size_memop(l), attrs); } else { /* RAM case */ ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false); @@ -3425,8 +3330,9 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, /* I/O case */ release_lock |= prepare_mmio_access(mr); l = memory_access_size(mr, l, addr1); - result |= memory_region_dispatch_read(mr, addr1, &val, l, attrs); - stn_p(buf, l, val); + result |= memory_region_dispatch_read(mr, addr1, &val, + size_memop(l), attrs); + stn_he_p(buf, l, val); } else { /* RAM case */ ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false); @@ -1820,11 +1820,15 @@ static void handle_read_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx) static void handle_file_io(GdbCmdContext *gdb_ctx, void *user_ctx) { - if (gdb_ctx->num_params >= 2 && gdb_ctx->s->current_syscall_cb) { + if (gdb_ctx->num_params >= 1 && gdb_ctx->s->current_syscall_cb) { target_ulong ret, err; ret = (target_ulong)gdb_ctx->params[0].val_ull; - err = (target_ulong)gdb_ctx->params[1].val_ull; + if (gdb_ctx->num_params >= 2) { + err = (target_ulong)gdb_ctx->params[1].val_ull; + } else { + err = 0; + } gdb_ctx->s->current_syscall_cb(gdb_ctx->s->c_cpu, ret, err); gdb_ctx->s->current_syscall_cb = NULL; } @@ -2588,7 +2592,9 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) break; } - run_cmd_parser(s, line_buf, cmd_parser); + if (cmd_parser) { + run_cmd_parser(s, line_buf, cmd_parser); + } return RS_IDLE; } diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 555c24f21d..78aee1a2f9 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -25,6 +25,7 @@ #include "qemu/bswap.h" #include "qemu/bitops.h" #include "sysemu/numa.h" +#include "hw/boards.h" static GArray *build_alloc_array(void) { @@ -1726,18 +1727,21 @@ void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base, * ACPI spec 5.2.17 System Locality Distance Information Table * (Revision 2.0 or later) */ -void build_slit(GArray *table_data, BIOSLinker *linker) +void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms) { int slit_start, i, j; slit_start = table_data->len; + int nb_numa_nodes = ms->numa_state->num_nodes; acpi_data_push(table_data, sizeof(AcpiTableHeader)); build_append_int_noprefix(table_data, nb_numa_nodes, 8); for (i = 0; i < nb_numa_nodes; i++) { for (j = 0; j < nb_numa_nodes; j++) { - assert(numa_info[i].distance[j]); - build_append_int_noprefix(table_data, numa_info[i].distance[j], 1); + assert(ms->numa_state->nodes[i].distance[j]); + build_append_int_noprefix(table_data, + ms->numa_state->nodes[i].distance[j], + 1); } } diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 73810a4440..118032c8c7 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -30,7 +30,8 @@ static void aw_a10_init(Object *obj) AwA10State *s = AW_A10(obj); object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu), - "cortex-a8-" TYPE_ARM_CPU, &error_abort, NULL); + ARM_CPU_TYPE_NAME("cortex-a8"), + &error_abort, NULL); sysbus_init_child_obj(obj, "intc", &s->intc, sizeof(s->intc), TYPE_AW_A10_PIC); diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 7a2e885e0b..13e208c78c 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -242,9 +242,6 @@ static void aspeed_board_init(MachineState *machine, write_boot_rom(drive0, FIRMWARE_ADDR, fl->size, &error_abort); } - aspeed_board_binfo.kernel_filename = machine->kernel_filename; - aspeed_board_binfo.initrd_filename = machine->initrd_filename; - aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline; aspeed_board_binfo.ram_size = ram_size; aspeed_board_binfo.loader_start = sc->info->memmap[ASPEED_SDRAM]; aspeed_board_binfo.nb_cpus = bmc->soc.num_cpus; @@ -253,7 +250,7 @@ static void aspeed_board_init(MachineState *machine, cfg->i2c_init(bmc); } - arm_load_kernel(ARM_CPU(first_cpu), &aspeed_board_binfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo); } static void palmetto_bmc_i2c_init(AspeedBoardState *bmc) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index eff89ab80e..bf97ef3e33 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -17,6 +17,7 @@ #include "sysemu/kvm.h" #include "sysemu/sysemu.h" #include "sysemu/numa.h" +#include "hw/boards.h" #include "sysemu/reset.h" #include "hw/loader.h" #include "elf.h" @@ -523,7 +524,7 @@ static void fdt_add_psci_node(void *fdt) } int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, - hwaddr addr_limit, AddressSpace *as) + hwaddr addr_limit, AddressSpace *as, MachineState *ms) { void *fdt = NULL; int size, rc, n = 0; @@ -597,10 +598,10 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, } g_strfreev(node_path); - if (nb_numa_nodes > 0) { + if (ms->numa_state != NULL && ms->numa_state->num_nodes > 0) { mem_base = binfo->loader_start; - for (i = 0; i < nb_numa_nodes; i++) { - mem_len = numa_info[i].node_mem; + for (i = 0; i < ms->numa_state->num_nodes; i++) { + mem_len = ms->numa_state->nodes[i].node_mem; rc = fdt_add_memory_node(fdt, acells, mem_base, scells, mem_len, i); if (rc < 0) { @@ -626,9 +627,9 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, qemu_fdt_add_subnode(fdt, "/chosen"); } - if (binfo->kernel_cmdline && *binfo->kernel_cmdline) { + if (ms->kernel_cmdline && *ms->kernel_cmdline) { rc = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", - binfo->kernel_cmdline); + ms->kernel_cmdline); if (rc < 0) { fprintf(stderr, "couldn't set /chosen/bootargs\n"); goto fail; @@ -1260,7 +1261,7 @@ static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info) */ } -void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) +void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info) { CPUState *cs; AddressSpace *as = arm_boot_address_space(cpu, info); @@ -1281,7 +1282,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) * doesn't support secure. */ assert(!(info->secure_board_setup && kvm_enabled())); - + info->kernel_filename = ms->kernel_filename; + info->kernel_cmdline = ms->kernel_cmdline; + info->initrd_filename = ms->initrd_filename; info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); info->dtb_limit = 0; @@ -1293,7 +1296,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) } if (!info->skip_dtb_autoload && have_dtb(info)) { - if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as) < 0) { + if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as, ms) < 0) { exit(1); } } diff --git a/hw/arm/collie.c b/hw/arm/collie.c index 219643c633..b1288ccea8 100644 --- a/hw/arm/collie.c +++ b/hw/arm/collie.c @@ -25,9 +25,6 @@ static struct arm_boot_info collie_binfo = { static void collie_init(MachineState *machine) { - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; StrongARMState *s; DriveInfo *dinfo; MemoryRegion *sysmem = get_system_memory(); @@ -46,11 +43,8 @@ static void collie_init(MachineState *machine) sysbus_create_simple("scoop", 0x40800000, NULL); - collie_binfo.kernel_filename = kernel_filename; - collie_binfo.kernel_cmdline = kernel_cmdline; - collie_binfo.initrd_filename = initrd_filename; collie_binfo.board_id = 0x208; - arm_load_kernel(s->cpu, &collie_binfo); + arm_load_kernel(s->cpu, machine, &collie_binfo); } static void collie_machine_init(MachineClass *mc) diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 38e0ca0f53..6dc2f1d6b6 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -73,15 +73,13 @@ static void cubieboard_init(MachineState *machine) /* TODO create and connect IDE devices for ide_drive_get() */ cubieboard_binfo.ram_size = machine->ram_size; - cubieboard_binfo.kernel_filename = machine->kernel_filename; - cubieboard_binfo.kernel_cmdline = machine->kernel_cmdline; - cubieboard_binfo.initrd_filename = machine->initrd_filename; - arm_load_kernel(&s->a10->cpu, &cubieboard_binfo); + arm_load_kernel(&s->a10->cpu, machine, &cubieboard_binfo); } static void cubieboard_machine_init(MachineClass *mc) { - mc->desc = "cubietech cubieboard"; + mc->desc = "cubietech cubieboard (Cortex-A9)"; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9"); mc->init = cubieboard_init; mc->block_default_type = IF_IDE; mc->units_per_default_bus = 1; diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 4f52465875..22434a65a2 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -37,7 +37,8 @@ static void digic_init(Object *obj) int i; object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu), - "arm946-" TYPE_ARM_CPU, &error_abort, NULL); + ARM_CPU_TYPE_NAME("arm946"), + &error_abort, NULL); for (i = 0; i < DIGIC4_NB_TIMERS; i++) { #define DIGIC_TIMER_NAME_MLEN 11 diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index f69358a5ba..09da52876d 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -122,17 +122,14 @@ exynos4_boards_init_common(MachineState *machine, exynos4_board_binfo.board_id = exynos4_board_id[board_type]; exynos4_board_binfo.smp_bootreg_addr = exynos4_board_smp_bootreg_addr[board_type]; - exynos4_board_binfo.kernel_filename = machine->kernel_filename; - exynos4_board_binfo.initrd_filename = machine->initrd_filename; - exynos4_board_binfo.kernel_cmdline = machine->kernel_cmdline; exynos4_board_binfo.gic_cpu_if_addr = EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100; exynos4_boards_init_ram(s, get_system_memory(), exynos4_board_ram_size[board_type]); - object_initialize(&s->soc, sizeof(s->soc), TYPE_EXYNOS4210_SOC); - qdev_set_parent_bus(DEVICE(&s->soc), sysbus_get_default()); + sysbus_init_child_obj(OBJECT(machine), "soc", + &s->soc, sizeof(s->soc), TYPE_EXYNOS4210_SOC); object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); @@ -143,7 +140,7 @@ static void nuri_init(MachineState *machine) { exynos4_boards_init_common(machine, EXYNOS4_BOARD_NURI); - arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &exynos4_board_binfo); } static void smdkc210_init(MachineState *machine) @@ -153,7 +150,7 @@ static void smdkc210_init(MachineState *machine) lan9215_init(SMDK_LAN9118_BASE_ADDR, qemu_irq_invert(s->soc.irq_table[exynos4210_get_irq(37, 1)])); - arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &exynos4_board_binfo); } static void nuri_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index 532d088298..3cb5a8fdfd 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -36,7 +36,9 @@ static void fsl_imx25_init(Object *obj) FslIMX25State *s = FSL_IMX25(obj); int i; - object_initialize(&s->cpu, sizeof(s->cpu), "arm926-" TYPE_ARM_CPU); + object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu), + ARM_CPU_TYPE_NAME("arm926"), + &error_abort, NULL); sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic), TYPE_IMX_AVIC); diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 1a37a7b997..55e90d104b 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -33,7 +33,9 @@ static void fsl_imx31_init(Object *obj) FslIMX31State *s = FSL_IMX31(obj); int i; - object_initialize(&s->cpu, sizeof(s->cpu), "arm1136-" TYPE_ARM_CPU); + object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu), + ARM_CPU_TYPE_NAME("arm1136"), + &error_abort, NULL); sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic), TYPE_IMX_AVIC); diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 8c397ef04b..552145b24e 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -43,7 +43,8 @@ static void fsl_imx6_init(Object *obj) for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX6_NUM_CPUS); i++) { snprintf(name, NAME_SIZE, "cpu%d", i); object_initialize_child(obj, name, &s->cpu[i], sizeof(s->cpu[i]), - "cortex-a9-" TYPE_ARM_CPU, &error_abort, NULL); + ARM_CPU_TYPE_NAME("cortex-a9"), + &error_abort, NULL); } sysbus_init_child_obj(obj, "a9mpcore", &s->a9mpcore, sizeof(s->a9mpcore), diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index b074177a71..c405b68d1d 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -34,7 +34,7 @@ static void fsl_imx6ul_init(Object *obj) int i; object_initialize_child(obj, "cpu0", &s->cpu, sizeof(s->cpu), - "cortex-a7-" TYPE_ARM_CPU, &error_abort, NULL); + ARM_CPU_TYPE_NAME("cortex-a7"), &error_abort, NULL); /* * A7MPCORE diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 362e5ba044..f1724d6929 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -236,9 +236,6 @@ enum cxmachines { static void calxeda_init(MachineState *machine, enum cxmachines machine_id) { ram_addr_t ram_size = machine->ram_size; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; DeviceState *dev = NULL; SysBusDevice *busdev; qemu_irq pic[128]; @@ -390,9 +387,6 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) /* TODO create and connect IDE devices for ide_drive_get() */ highbank_binfo.ram_size = ram_size; - highbank_binfo.kernel_filename = kernel_filename; - highbank_binfo.kernel_cmdline = kernel_cmdline; - highbank_binfo.initrd_filename = initrd_filename; /* highbank requires a dtb in order to boot, and the dtb will override * the board ID. The following value is ignored, so set it to -1 to be * clear that the value is meaningless. @@ -412,7 +406,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) "may not boot."); } - arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &highbank_binfo); } static void highbank_init(MachineState *machine) diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 5d673e47bc..c76fc2bd94 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -116,9 +116,6 @@ static void imx25_pdk_init(MachineState *machine) } imx25_pdk_binfo.ram_size = machine->ram_size; - imx25_pdk_binfo.kernel_filename = machine->kernel_filename; - imx25_pdk_binfo.kernel_cmdline = machine->kernel_cmdline; - imx25_pdk_binfo.initrd_filename = machine->initrd_filename; imx25_pdk_binfo.loader_start = FSL_IMX25_SDRAM0_ADDR; imx25_pdk_binfo.board_id = 1771, imx25_pdk_binfo.nb_cpus = 1; @@ -129,7 +126,7 @@ static void imx25_pdk_init(MachineState *machine) * fail. */ if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu, &imx25_pdk_binfo); + arm_load_kernel(&s->soc.cpu, machine, &imx25_pdk_binfo); } } diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 200568b42a..524970840d 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -582,9 +582,6 @@ static struct arm_boot_info integrator_binfo = { static void integratorcp_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; Object *cpuobj; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); @@ -654,10 +651,7 @@ static void integratorcp_init(MachineState *machine) sysbus_create_simple("pl110", 0xc0000000, pic[22]); integrator_binfo.ram_size = ram_size; - integrator_binfo.kernel_filename = kernel_filename; - integrator_binfo.kernel_cmdline = kernel_cmdline; - integrator_binfo.initrd_filename = initrd_filename; - arm_load_kernel(cpu, &integrator_binfo); + arm_load_kernel(cpu, machine, &integrator_binfo); } static void integratorcp_machine_init(MachineClass *mc) diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c index 2f052e1f8c..1d5ef289d5 100644 --- a/hw/arm/kzm.c +++ b/hw/arm/kzm.c @@ -127,13 +127,10 @@ static void kzm_init(MachineState *machine) } kzm_binfo.ram_size = machine->ram_size; - kzm_binfo.kernel_filename = machine->kernel_filename; - kzm_binfo.kernel_cmdline = machine->kernel_cmdline; - kzm_binfo.initrd_filename = machine->initrd_filename; kzm_binfo.nb_cpus = 1; if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu, &kzm_binfo); + arm_load_kernel(&s->soc.cpu, machine, &kzm_binfo); } } diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c index 1bad1aea76..b01ce3ce08 100644 --- a/hw/arm/mainstone.c +++ b/hw/arm/mainstone.c @@ -176,11 +176,8 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, smc91c111_init(&nd_table[0], MST_ETH_PHYS, qdev_get_gpio_in(mst_irq, ETHERNET_IRQ)); - mainstone_binfo.kernel_filename = machine->kernel_filename; - mainstone_binfo.kernel_cmdline = machine->kernel_cmdline; - mainstone_binfo.initrd_filename = machine->initrd_filename; mainstone_binfo.board_id = arm_id; - arm_load_kernel(mpu->cpu, &mainstone_binfo); + arm_load_kernel(mpu->cpu, machine, &mainstone_binfo); } static void mainstone_init(MachineState *machine) diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c index 0276875f02..e90b393a44 100644 --- a/hw/arm/mcimx6ul-evk.c +++ b/hw/arm/mcimx6ul-evk.c @@ -40,9 +40,6 @@ static void mcimx6ul_evk_init(MachineState *machine) .loader_start = FSL_IMX6UL_MMDC_ADDR, .board_id = -1, .ram_size = machine->ram_size, - .kernel_filename = machine->kernel_filename, - .kernel_cmdline = machine->kernel_cmdline, - .initrd_filename = machine->initrd_filename, .nb_cpus = machine->smp.cpus, }; @@ -72,7 +69,7 @@ static void mcimx6ul_evk_init(MachineState *machine) } if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu, &boot_info); + arm_load_kernel(&s->soc.cpu, machine, &boot_info); } } diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c index 97b8bb788a..0d1f62d30a 100644 --- a/hw/arm/mcimx7d-sabre.c +++ b/hw/arm/mcimx7d-sabre.c @@ -30,7 +30,6 @@ static void mcimx7d_sabre_init(MachineState *machine) { static struct arm_boot_info boot_info; MCIMX7Sabre *s = g_new0(MCIMX7Sabre, 1); - Object *soc; int i; if (machine->ram_size > FSL_IMX7_MMDC_SIZE) { @@ -43,16 +42,13 @@ static void mcimx7d_sabre_init(MachineState *machine) .loader_start = FSL_IMX7_MMDC_ADDR, .board_id = -1, .ram_size = machine->ram_size, - .kernel_filename = machine->kernel_filename, - .kernel_cmdline = machine->kernel_cmdline, - .initrd_filename = machine->initrd_filename, .nb_cpus = machine->smp.cpus, }; - object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX7); - soc = OBJECT(&s->soc); - object_property_add_child(OBJECT(machine), "soc", soc, &error_fatal); - object_property_set_bool(soc, true, "realized", &error_fatal); + object_initialize_child(OBJECT(machine), "soc", + &s->soc, sizeof(s->soc), + TYPE_FSL_IMX7, &error_fatal, NULL); + object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); memory_region_allocate_system_memory(&s->ram, NULL, "mcimx7d-sabre.ram", machine->ram_size); @@ -75,7 +71,7 @@ static void mcimx7d_sabre_init(MachineState *machine) } if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu[0], &boot_info); + arm_load_kernel(&s->soc.cpu[0], machine, &boot_info); } } diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index d85dc2c4bd..6b24aaacde 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -427,10 +427,10 @@ static void mps2tz_common_init(MachineState *machine) /* The sec_resp_cfg output from the IoTKit must be split into multiple * lines, one for each of the PPCs we create here, plus one per MSC. */ - object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter), - TYPE_SPLIT_IRQ); - object_property_add_child(OBJECT(machine), "sec-resp-splitter", - OBJECT(&mms->sec_resp_splitter), &error_abort); + object_initialize_child(OBJECT(machine), "sec-resp-splitter", + &mms->sec_resp_splitter, + sizeof(mms->sec_resp_splitter), + TYPE_SPLIT_IRQ, &error_abort, NULL); object_property_set_int(OBJECT(&mms->sec_resp_splitter), ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc), "num-lines", &error_fatal); @@ -465,10 +465,9 @@ static void mps2tz_common_init(MachineState *machine) * Tx, Rx and "combined" IRQs are sent to the NVIC separately. * Create the OR gate for this. */ - object_initialize(&mms->uart_irq_orgate, sizeof(mms->uart_irq_orgate), - TYPE_OR_IRQ); - object_property_add_child(OBJECT(mms), "uart-irq-orgate", - OBJECT(&mms->uart_irq_orgate), &error_abort); + object_initialize_child(OBJECT(mms), "uart-irq-orgate", + &mms->uart_irq_orgate, sizeof(mms->uart_irq_orgate), + TYPE_OR_IRQ, &error_abort, NULL); object_property_set_int(OBJECT(&mms->uart_irq_orgate), 10, "num-lines", &error_fatal); object_property_set_bool(OBJECT(&mms->uart_irq_orgate), true, diff --git a/hw/arm/musca.c b/hw/arm/musca.c index ddd8842732..68db4b5b38 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -424,10 +424,11 @@ static void musca_init(MachineState *machine) * The sec_resp_cfg output from the SSE-200 must be split into multiple * lines, one for each of the PPCs we create here. */ - object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter), - TYPE_SPLIT_IRQ); - object_property_add_child(OBJECT(machine), "sec-resp-splitter", - OBJECT(&mms->sec_resp_splitter), &error_fatal); + object_initialize_child(OBJECT(machine), "sec-resp-splitter", + &mms->sec_resp_splitter, + sizeof(mms->sec_resp_splitter), + TYPE_SPLIT_IRQ, &error_fatal, NULL); + object_property_set_int(OBJECT(&mms->sec_resp_splitter), ARRAY_SIZE(mms->ppc), "num-lines", &error_fatal); object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true, diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 8ae4751d75..246cbb1336 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1573,9 +1573,6 @@ static struct arm_boot_info musicpal_binfo = { static void musicpal_init(MachineState *machine) { - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; ARMCPU *cpu; qemu_irq pic[32]; DeviceState *dev; @@ -1704,10 +1701,7 @@ static void musicpal_init(MachineState *machine) sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]); musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE; - musicpal_binfo.kernel_filename = kernel_filename; - musicpal_binfo.kernel_cmdline = kernel_cmdline; - musicpal_binfo.initrd_filename = initrd_filename; - arm_load_kernel(cpu, &musicpal_binfo); + arm_load_kernel(cpu, machine, &musicpal_binfo); } static void musicpal_machine_init(MachineClass *mc) diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index a6c4085337..a36971d39a 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -1361,10 +1361,7 @@ static void n8x0_init(MachineState *machine, if (machine->kernel_filename) { /* Or at the linux loader. */ - binfo->kernel_filename = machine->kernel_filename; - binfo->kernel_cmdline = machine->kernel_cmdline; - binfo->initrd_filename = machine->initrd_filename; - arm_load_kernel(s->mpu->cpu, binfo); + arm_load_kernel(s->mpu->cpu, machine, binfo); qemu_register_reset(n8x0_boot_init, s); } diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c index 75a05c36b0..c071197be7 100644 --- a/hw/arm/omap_sx1.c +++ b/hw/arm/omap_sx1.c @@ -195,10 +195,7 @@ static void sx1_init(MachineState *machine, const int version) } /* Load the kernel. */ - sx1_binfo.kernel_filename = machine->kernel_filename; - sx1_binfo.kernel_cmdline = machine->kernel_cmdline; - sx1_binfo.initrd_filename = machine->initrd_filename; - arm_load_kernel(mpu->cpu, &sx1_binfo); + arm_load_kernel(mpu->cpu, machine, &sx1_binfo); /* TODO: fix next line */ //~ qemu_console_resize(ds, 640, 480); diff --git a/hw/arm/palm.c b/hw/arm/palm.c index bea47b917d..02a3a82b9b 100644 --- a/hw/arm/palm.c +++ b/hw/arm/palm.c @@ -187,9 +187,6 @@ static struct arm_boot_info palmte_binfo = { static void palmte_init(MachineState *machine) { - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); struct omap_mpu_state_s *mpu; int flash_size = 0x00800000; @@ -249,16 +246,13 @@ static void palmte_init(MachineState *machine) } } - if (!rom_loaded && !kernel_filename && !qtest_enabled()) { + if (!rom_loaded && !machine->kernel_filename && !qtest_enabled()) { fprintf(stderr, "Kernel or ROM image must be specified\n"); exit(1); } /* Load the kernel. */ - palmte_binfo.kernel_filename = kernel_filename; - palmte_binfo.kernel_cmdline = kernel_cmdline; - palmte_binfo.initrd_filename = initrd_filename; - arm_load_kernel(mpu->cpu, &palmte_binfo); + arm_load_kernel(mpu->cpu, machine, &palmte_binfo); } static void palmte_machine_init(MachineClass *mc) diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 5b2620acb4..74c062d05e 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -157,13 +157,9 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size) binfo.entry = firmware_addr; binfo.firmware_loaded = true; - } else { - binfo.kernel_filename = machine->kernel_filename; - binfo.kernel_cmdline = machine->kernel_cmdline; - binfo.initrd_filename = machine->initrd_filename; } - arm_load_kernel(ARM_CPU(first_cpu), &binfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &binfo); } static void raspi_init(MachineState *machine, int version) diff --git a/hw/arm/realview.c b/hw/arm/realview.c index b108a9ab26..8fcdf75a2b 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -351,13 +351,10 @@ static void realview_init(MachineState *machine, memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack); realview_binfo.ram_size = ram_size; - realview_binfo.kernel_filename = machine->kernel_filename; - realview_binfo.kernel_cmdline = machine->kernel_cmdline; - realview_binfo.initrd_filename = machine->initrd_filename; realview_binfo.nb_cpus = smp_cpus; realview_binfo.board_id = realview_board_id[board_type]; realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0); - arm_load_kernel(ARM_CPU(first_cpu), &realview_binfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &realview_binfo); } static void realview_eb_init(MachineState *machine) diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index a6185c169e..96cc455c5c 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -103,16 +103,13 @@ static void sabrelite_init(MachineState *machine) } sabrelite_binfo.ram_size = machine->ram_size; - sabrelite_binfo.kernel_filename = machine->kernel_filename; - sabrelite_binfo.kernel_cmdline = machine->kernel_cmdline; - sabrelite_binfo.initrd_filename = machine->initrd_filename; sabrelite_binfo.nb_cpus = machine->smp.cpus; sabrelite_binfo.secure_boot = true; sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary; sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary; if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu[0], &sabrelite_binfo); + arm_load_kernel(&s->soc.cpu[0], machine, &sabrelite_binfo); } } diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index e98e9a5170..27046cc284 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -146,6 +146,7 @@ static void create_fdt(SBSAMachineState *sms) { void *fdt = create_device_tree(&sms->fdt_size); const MachineState *ms = MACHINE(sms); + int nb_numa_nodes = ms->numa_state->num_nodes; int cpu; if (!fdt) { @@ -159,7 +160,7 @@ static void create_fdt(SBSAMachineState *sms) qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2); qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2); - if (have_numa_distance) { + if (ms->numa_state->have_numa_distance) { int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t); uint32_t *matrix = g_malloc0(size); int idx, i, j; @@ -169,7 +170,8 @@ static void create_fdt(SBSAMachineState *sms) idx = (i * nb_numa_nodes + j) * 3; matrix[idx + 0] = cpu_to_be32(i); matrix[idx + 1] = cpu_to_be32(j); - matrix[idx + 2] = cpu_to_be32(numa_info[i].distance[j]); + matrix[idx + 2] = + cpu_to_be32(ms->numa_state->nodes[i].distance[j]); } } @@ -711,13 +713,12 @@ static void sbsa_ref_init(MachineState *machine) create_pcie(sms, pic); sms->bootinfo.ram_size = machine->ram_size; - sms->bootinfo.kernel_filename = machine->kernel_filename; sms->bootinfo.nb_cpus = smp_cpus; sms->bootinfo.board_id = -1; sms->bootinfo.loader_start = sbsa_ref_memmap[SBSA_MEM].base; sms->bootinfo.get_dtb = sbsa_ref_dtb; sms->bootinfo.firmware_loaded = firmware_loaded; - arm_load_kernel(ARM_CPU(first_cpu), &sms->bootinfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &sms->bootinfo); } static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx) @@ -763,7 +764,7 @@ sbsa_ref_cpu_index_to_props(MachineState *ms, unsigned cpu_index) static int64_t sbsa_ref_get_default_cpu_node_id(const MachineState *ms, int idx) { - return idx % nb_numa_nodes; + return idx % ms->numa_state->num_nodes; } static void sbsa_ref_instance_init(Object *obj) @@ -790,6 +791,7 @@ static void sbsa_ref_class_init(ObjectClass *oc, void *data) mc->possible_cpu_arch_ids = sbsa_ref_possible_cpu_arch_ids; mc->cpu_index_to_instance_props = sbsa_ref_cpu_index_to_props; mc->get_default_cpu_node_id = sbsa_ref_get_default_cpu_node_id; + mc->numa_mem_supported = true; } static const TypeInfo sbsa_ref_info = { diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index b160289cd1..d190181ef1 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -381,6 +381,7 @@ typedef struct SMMUEventInfo { uint32_t sid; bool recorded; bool record_trans_faults; + bool inval_ste_allowed; union { struct { uint32_t ssid; diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 2eaf07fb5f..db051dcac8 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -320,6 +320,9 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg, uint32_t config; if (!STE_VALID(ste)) { + if (!event->inval_ste_allowed) { + qemu_log_mask(LOG_GUEST_ERROR, "invalid STE\n"); + } goto bad_ste; } @@ -406,8 +409,10 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, if (!span) { /* l2ptr is not valid */ - qemu_log_mask(LOG_GUEST_ERROR, - "invalid sid=%d (L1STD span=0)\n", sid); + if (!event->inval_ste_allowed) { + qemu_log_mask(LOG_GUEST_ERROR, + "invalid sid=%d (L1STD span=0)\n", sid); + } event->type = SMMU_EVT_C_BAD_STREAMID; return -EINVAL; } @@ -602,7 +607,9 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr, SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu); SMMUv3State *s = sdev->smmu; uint32_t sid = smmu_get_sid(sdev); - SMMUEventInfo event = {.type = SMMU_EVT_NONE, .sid = sid}; + SMMUEventInfo event = {.type = SMMU_EVT_NONE, + .sid = sid, + .inval_ste_allowed = false}; SMMUPTWEventInfo ptw_info = {}; SMMUTranslationStatus status; SMMUState *bs = ARM_SMMU(s); @@ -795,16 +802,13 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, dma_addr_t iova) { SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu); - SMMUEventInfo event = {}; + SMMUEventInfo event = {.inval_ste_allowed = true}; SMMUTransTableInfo *tt; SMMUTransCfg *cfg; IOMMUTLBEntry entry; cfg = smmuv3_get_config(sdev, &event); if (!cfg) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s error decoding the configuration for iommu mr=%s\n", - __func__, mr->parent_obj.name); return; } diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 59348123b5..25bd0f5d9d 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -954,11 +954,8 @@ static void spitz_common_init(MachineState *machine, /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ spitz_microdrive_attach(mpu, 0); - spitz_binfo.kernel_filename = machine->kernel_filename; - spitz_binfo.kernel_cmdline = machine->kernel_cmdline; - spitz_binfo.initrd_filename = machine->initrd_filename; spitz_binfo.board_id = arm_id; - arm_load_kernel(mpu->cpu, &spitz_binfo); + arm_load_kernel(mpu->cpu, machine, &spitz_binfo); sl_bootparam_write(SL_PXA_PARAM_BASE); } diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index e9627e356e..4d95a1f3e2 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -218,9 +218,6 @@ static struct arm_boot_info tosa_binfo = { static void tosa_init(MachineState *machine) { - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); PXA2xxState *mpu; @@ -245,11 +242,8 @@ static void tosa_init(MachineState *machine) tosa_tg_init(mpu); - tosa_binfo.kernel_filename = kernel_filename; - tosa_binfo.kernel_cmdline = kernel_cmdline; - tosa_binfo.initrd_filename = initrd_filename; tosa_binfo.board_id = 0x208; - arm_load_kernel(mpu->cpu, &tosa_binfo); + arm_load_kernel(mpu->cpu, machine, &tosa_binfo); sl_bootparam_write(SL_PXA_PARAM_BASE); } diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index e25561705f..e86af01537 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -375,11 +375,8 @@ static void versatile_init(MachineState *machine, int board_id) } versatile_binfo.ram_size = machine->ram_size; - versatile_binfo.kernel_filename = machine->kernel_filename; - versatile_binfo.kernel_cmdline = machine->kernel_cmdline; - versatile_binfo.initrd_filename = machine->initrd_filename; versatile_binfo.board_id = board_id; - arm_load_kernel(cpu, &versatile_binfo); + arm_load_kernel(cpu, machine, &versatile_binfo); } static void vpb_init(MachineState *machine) diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 5d932c27c0..4673a88a8d 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -707,9 +707,6 @@ static void vexpress_common_init(MachineState *machine) } daughterboard->bootinfo.ram_size = machine->ram_size; - daughterboard->bootinfo.kernel_filename = machine->kernel_filename; - daughterboard->bootinfo.kernel_cmdline = machine->kernel_cmdline; - daughterboard->bootinfo.initrd_filename = machine->initrd_filename; daughterboard->bootinfo.nb_cpus = machine->smp.cpus; daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID; daughterboard->bootinfo.loader_start = daughterboard->loader_start; @@ -719,7 +716,7 @@ static void vexpress_common_init(MachineState *machine) daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb; /* When booting Linux we should be in secure state if the CPU has one. */ daughterboard->bootinfo.secure_boot = vms->secure; - arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &daughterboard->bootinfo); } static bool vexpress_get_secure(Object *obj, Error **errp) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index a8b2d97fe9..6cdf156cf5 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -517,7 +517,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) int i, srat_start; uint64_t mem_base; MachineClass *mc = MACHINE_GET_CLASS(vms); - const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(MACHINE(vms)); + MachineState *ms = MACHINE(vms); + const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(ms); srat_start = table_data->len; srat = acpi_data_push(table_data, sizeof(*srat)); @@ -533,12 +534,13 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } mem_base = vms->memmap[VIRT_MEM].base; - for (i = 0; i < nb_numa_nodes; ++i) { - if (numa_info[i].node_mem > 0) { + for (i = 0; i < ms->numa_state->num_nodes; ++i) { + if (ms->numa_state->nodes[i].node_mem > 0) { numamem = acpi_data_push(table_data, sizeof(*numamem)); - build_srat_memory(numamem, mem_base, numa_info[i].node_mem, i, + build_srat_memory(numamem, mem_base, + ms->numa_state->nodes[i].node_mem, i, MEM_AFFINITY_ENABLED); - mem_base += numa_info[i].node_mem; + mem_base += ms->numa_state->nodes[i].node_mem; } } @@ -759,6 +761,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) GArray *table_offsets; unsigned dsdt, xsdt; GArray *tables_blob = tables->table_data; + MachineState *ms = MACHINE(vms); table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); @@ -793,12 +796,12 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_spcr(tables_blob, tables->linker, vms); - if (nb_numa_nodes > 0) { + if (ms->numa_state->num_nodes > 0) { acpi_add_table(table_offsets, tables_blob); build_srat(tables_blob, tables->linker, vms); - if (have_numa_distance) { + if (ms->numa_state->have_numa_distance) { acpi_add_table(table_offsets, tables_blob); - build_slit(tables_blob, tables->linker); + build_slit(tables_blob, tables->linker, ms); } } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 0d1629ccb3..d74538b021 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -203,6 +203,8 @@ static bool cpu_type_valid(const char *cpu) static void create_fdt(VirtMachineState *vms) { + MachineState *ms = MACHINE(vms); + int nb_numa_nodes = ms->numa_state->num_nodes; void *fdt = create_device_tree(&vms->fdt_size); if (!fdt) { @@ -234,7 +236,7 @@ static void create_fdt(VirtMachineState *vms) "clk24mhz"); qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vms->clock_phandle); - if (have_numa_distance) { + if (nb_numa_nodes > 0 && ms->numa_state->have_numa_distance) { int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t); uint32_t *matrix = g_malloc0(size); int idx, i, j; @@ -244,7 +246,8 @@ static void create_fdt(VirtMachineState *vms) idx = (i * nb_numa_nodes + j) * 3; matrix[idx + 0] = cpu_to_be32(i); matrix[idx + 1] = cpu_to_be32(j); - matrix[idx + 2] = cpu_to_be32(numa_info[i].distance[j]); + matrix[idx + 2] = + cpu_to_be32(ms->numa_state->nodes[i].distance[j]); } } @@ -1368,6 +1371,7 @@ void virt_machine_done(Notifier *notifier, void *data) { VirtMachineState *vms = container_of(notifier, VirtMachineState, machine_done); + MachineState *ms = MACHINE(vms); ARMCPU *cpu = ARM_CPU(first_cpu); struct arm_boot_info *info = &vms->bootinfo; AddressSpace *as = arm_boot_address_space(cpu, info); @@ -1385,7 +1389,7 @@ void virt_machine_done(Notifier *notifier, void *data) vms->memmap[VIRT_PLATFORM_BUS].size, vms->irqmap[VIRT_PLATFORM_BUS]); } - if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as) < 0) { + if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as, ms) < 0) { exit(1); } @@ -1711,16 +1715,13 @@ static void machvirt_init(MachineState *machine) create_platform_bus(vms, pic); vms->bootinfo.ram_size = machine->ram_size; - vms->bootinfo.kernel_filename = machine->kernel_filename; - vms->bootinfo.kernel_cmdline = machine->kernel_cmdline; - vms->bootinfo.initrd_filename = machine->initrd_filename; vms->bootinfo.nb_cpus = smp_cpus; vms->bootinfo.board_id = -1; vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base; vms->bootinfo.get_dtb = machvirt_dtb; vms->bootinfo.skip_dtb_autoload = true; vms->bootinfo.firmware_loaded = firmware_loaded; - arm_load_kernel(ARM_CPU(first_cpu), &vms->bootinfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo); vms->machine_done.notify = virt_machine_done; qemu_add_machine_init_done_notifier(&vms->machine_done); @@ -1848,7 +1849,7 @@ virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index) static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx) { - return idx % nb_numa_nodes; + return idx % ms->numa_state->num_nodes; } static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 89da34808b..c14774e542 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -158,9 +158,6 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, static void zynq_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ext_ram = g_new(MemoryRegion, 1); @@ -303,16 +300,13 @@ static void zynq_init(MachineState *machine) sysbus_mmio_map(busdev, 0, 0xF8007000); zynq_binfo.ram_size = ram_size; - zynq_binfo.kernel_filename = kernel_filename; - zynq_binfo.kernel_cmdline = kernel_cmdline; - zynq_binfo.initrd_filename = initrd_filename; zynq_binfo.nb_cpus = 1; zynq_binfo.board_id = 0xd32; zynq_binfo.loader_start = 0; zynq_binfo.board_setup_addr = BOARD_SETUP_ADDR; zynq_binfo.write_board_setup = zynq_write_board_setup; - arm_load_kernel(ARM_CPU(first_cpu), &zynq_binfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &zynq_binfo); } static void zynq_machine_init(MachineClass *mc) diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index f95fde2309..462493c467 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -441,14 +441,11 @@ static void versal_virt_init(MachineState *machine) 0, &s->soc.fpd.apu.mr, 0); s->binfo.ram_size = machine->ram_size; - s->binfo.kernel_filename = machine->kernel_filename; - s->binfo.kernel_cmdline = machine->kernel_cmdline; - s->binfo.initrd_filename = machine->initrd_filename; s->binfo.loader_start = 0x0; s->binfo.get_dtb = versal_virt_get_dtb; s->binfo.modify_dtb = versal_virt_modify_dtb; if (machine->kernel_filename) { - arm_load_kernel(s->soc.fpd.apu.cpu[0], &s->binfo); + arm_load_kernel(s->soc.fpd.apu.cpu[0], machine, &s->binfo); } else { AddressSpace *as = arm_boot_address_space(s->soc.fpd.apu.cpu[0], &s->binfo); @@ -457,7 +454,7 @@ static void versal_virt_init(MachineState *machine) s->binfo.loader_start = 0x1000; s->binfo.dtb_limit = 0x1000000; if (arm_load_dtb(s->binfo.loader_start, - &s->binfo, s->binfo.dtb_limit, as) < 0) { + &s->binfo, s->binfo.dtb_limit, as, machine) < 0) { exit(EXIT_FAILURE); } } diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 044d3394c0..53cfe7c1f1 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -171,11 +171,8 @@ static void xlnx_zcu102_init(MachineState *machine) /* TODO create and connect IDE devices for ide_drive_get() */ xlnx_zcu102_binfo.ram_size = ram_size; - xlnx_zcu102_binfo.kernel_filename = machine->kernel_filename; - xlnx_zcu102_binfo.kernel_cmdline = machine->kernel_cmdline; - xlnx_zcu102_binfo.initrd_filename = machine->initrd_filename; xlnx_zcu102_binfo.loader_start = 0; - arm_load_kernel(s->soc.boot_cpu_ptr, &xlnx_zcu102_binfo); + arm_load_kernel(s->soc.boot_cpu_ptr, machine, &xlnx_zcu102_binfo); } static void xlnx_zcu102_machine_instance_init(Object *obj) diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 0f587e63d3..fb03c60ebb 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -196,8 +196,8 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s, object_initialize_child(OBJECT(&s->rpu_cluster), "rpu-cpu[*]", &s->rpu_cpu[i], sizeof(s->rpu_cpu[i]), - "cortex-r5f-" TYPE_ARM_CPU, &error_abort, - NULL); + ARM_CPU_TYPE_NAME("cortex-r5f"), + &error_abort, NULL); name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i])); if (strcmp(name, boot_cpu)) { @@ -237,8 +237,8 @@ static void xlnx_zynqmp_init(Object *obj) for (i = 0; i < num_apus; i++) { object_initialize_child(OBJECT(&s->apu_cluster), "apu-cpu[*]", &s->apu_cpu[i], sizeof(s->apu_cpu[i]), - "cortex-a53-" TYPE_ARM_CPU, &error_abort, - NULL); + ARM_CPU_TYPE_NAME("cortex-a53"), + &error_abort, NULL); } sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 3923b87e4c..34794fe3ae 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -296,9 +296,6 @@ static const TypeInfo aer915_info = { static void z2_init(MachineState *machine) { - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); uint32_t sector_len = 0x10000; PXA2xxState *mpu; @@ -352,11 +349,8 @@ static void z2_init(MachineState *machine) qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS, qemu_allocate_irq(z2_lcd_cs, z2_lcd, 0)); - z2_binfo.kernel_filename = kernel_filename; - z2_binfo.kernel_cmdline = kernel_cmdline; - z2_binfo.initrd_filename = initrd_filename; z2_binfo.board_id = 0x6dd; - arm_load_kernel(mpu->cpu, &z2_binfo); + arm_load_kernel(mpu->cpu, machine, &z2_binfo); } static void z2_machine_init(MachineClass *mc) diff --git a/hw/char/escc.c b/hw/char/escc.c index e185522e27..8f7bf322cb 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -45,14 +45,21 @@ * mouse and keyboard ports don't implement all functions and they are * only asynchronous. There is no DMA. * - * Z85C30 is also used on PowerMacs. There are some small differences - * between Sparc version (sunzilog) and PowerMac (pmac): + * Z85C30 is also used on PowerMacs and m68k Macs. + * + * There are some small differences between Sparc version (sunzilog) + * and PowerMac (pmac): * Offset between control and data registers * There is some kind of lockup bug, but we can ignore it * CTS is inverted * DMA on pmac using DBDMA chip * pmac can do IRDA and faster rates, sunzilog can only do 38400 * pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz + * + * Linux driver for m68k Macs is the same as for PowerMac (pmac_zilog), + * but registers are grouped by type and not by channel: + * channel is selected by bit 0 of the address (instead of bit 1) + * and register is selected by bit 1 of the address (instead of bit 0). */ /* @@ -172,6 +179,16 @@ static void handle_kbd_command(ESCCChannelState *s, int val); static int serial_can_receive(void *opaque); static void serial_receive_byte(ESCCChannelState *s, int ch); +static int reg_shift(ESCCState *s) +{ + return s->bit_swap ? s->it_shift + 1 : s->it_shift; +} + +static int chn_shift(ESCCState *s) +{ + return s->bit_swap ? s->it_shift : s->it_shift + 1; +} + static void clear_queue(void *opaque) { ESCCChannelState *s = opaque; @@ -436,8 +453,8 @@ static void escc_mem_write(void *opaque, hwaddr addr, int newreg, channel; val &= 0xff; - saddr = (addr >> serial->it_shift) & 1; - channel = (addr >> (serial->it_shift + 1)) & 1; + saddr = (addr >> reg_shift(serial)) & 1; + channel = (addr >> chn_shift(serial)) & 1; s = &serial->chn[channel]; switch (saddr) { case SERIAL_CTRL: @@ -547,8 +564,8 @@ static uint64_t escc_mem_read(void *opaque, hwaddr addr, uint32_t ret; int channel; - saddr = (addr >> serial->it_shift) & 1; - channel = (addr >> (serial->it_shift + 1)) & 1; + saddr = (addr >> reg_shift(serial)) & 1; + channel = (addr >> chn_shift(serial)) & 1; s = &serial->chn[channel]; switch (saddr) { case SERIAL_CTRL: @@ -832,6 +849,7 @@ static void escc_realize(DeviceState *dev, Error **errp) static Property escc_properties[] = { DEFINE_PROP_UINT32("frequency", ESCCState, frequency, 0), DEFINE_PROP_UINT32("it_shift", ESCCState, it_shift, 0), + DEFINE_PROP_BOOL("bit_swap", ESCCState, bit_swap, false), DEFINE_PROP_UINT32("disabled", ESCCState, disabled, 0), DEFINE_PROP_UINT32("chnBtype", ESCCState, chn[0].type, 0), DEFINE_PROP_UINT32("chnAtype", ESCCState, chn[1].type, 0), diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index 1f66bda346..cd970cc4c5 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -23,6 +23,7 @@ #include "qapi/string-output-visitor.h" #include "qemu/error-report.h" #include "sysemu/numa.h" +#include "hw/boards.h" void hmp_info_cpus(Monitor *mon, const QDict *qdict) { @@ -139,15 +140,21 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict) void hmp_info_numa(Monitor *mon, const QDict *qdict) { - int i; + int i, nb_numa_nodes; NumaNodeMem *node_mem; CpuInfoList *cpu_list, *cpu; + MachineState *ms = MACHINE(qdev_get_machine()); + + nb_numa_nodes = ms->numa_state ? ms->numa_state->num_nodes : 0; + monitor_printf(mon, "%d nodes\n", nb_numa_nodes); + if (!nb_numa_nodes) { + return; + } cpu_list = qmp_query_cpus(&error_abort); node_mem = g_new0(NumaNodeMem, nb_numa_nodes); - query_numa_node_mem(node_mem); - monitor_printf(mon, "%d nodes\n", nb_numa_nodes); + query_numa_node_mem(node_mem, ms); for (i = 0; i < nb_numa_nodes; i++) { monitor_printf(mon, "node %d cpus:", i); for (cpu = cpu_list; cpu; cpu = cpu->next) { diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 15cf7c62e3..eed5aeb2f7 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -230,6 +230,10 @@ MachineInfoList *qmp_query_machines(Error **errp) info->hotpluggable_cpus = mc->has_hotpluggable_cpus; info->numa_mem_supported = mc->numa_mem_supported; info->deprecated = !!mc->deprecation_reason; + if (mc->default_cpu_type) { + info->default_cpu_type = g_strdup(mc->default_cpu_type); + info->has_default_cpu_type = true; + } entry = g_malloc0(sizeof(*entry)); entry->value = info; diff --git a/hw/core/machine.c b/hw/core/machine.c index 83cd1bfeec..1689ad3bf8 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -27,7 +27,9 @@ #include "hw/pci/pci.h" #include "hw/mem/nvdimm.h" -GlobalProperty hw_compat_4_1[] = {}; +GlobalProperty hw_compat_4_1[] = { + { "virtio-pci", "x-pcie-flr-init", "off" }, +}; const size_t hw_compat_4_1_len = G_N_ELEMENTS(hw_compat_4_1); GlobalProperty hw_compat_4_0[] = { @@ -956,6 +958,9 @@ static void machine_initfn(Object *obj) NULL); } + if (mc->numa_mem_supported) { + ms->numa_state = g_new0(NumaState, 1); + } /* Register notifier when init is done for sysbus sanity checks */ ms->sysbus_notifier.notify = machine_init_notify; @@ -976,6 +981,7 @@ static void machine_finalize(Object *obj) g_free(ms->firmware); g_free(ms->device_memory); g_free(ms->nvdimms_state); + g_free(ms->numa_state); } bool machine_usb(MachineState *machine) @@ -1050,7 +1056,7 @@ static void machine_numa_finish_cpu_init(MachineState *machine) MachineClass *mc = MACHINE_GET_CLASS(machine); const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(machine); - assert(nb_numa_nodes); + assert(machine->numa_state->num_nodes); for (i = 0; i < possible_cpus->len; i++) { if (possible_cpus->cpus[i].props.has_node_id) { break; @@ -1096,9 +1102,11 @@ void machine_run_board_init(MachineState *machine) { MachineClass *machine_class = MACHINE_GET_CLASS(machine); - numa_complete_configuration(machine); - if (nb_numa_nodes) { - machine_numa_finish_cpu_init(machine); + if (machine_class->numa_mem_supported) { + numa_complete_configuration(machine); + if (machine->numa_state->num_nodes) { + machine_numa_finish_cpu_init(machine); + } } /* If the machine supports the valid_cpu_types check and the user diff --git a/hw/core/numa.c b/hw/core/numa.c index 4f7e4628a0..4dfec5c95b 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -55,10 +55,6 @@ static int have_mem; static int max_numa_nodeid; /* Highest specified NUMA node ID, plus one. * For all nodes, nodeid < max_numa_nodeid */ -int nb_numa_nodes; -bool have_numa_distance; -NodeInfo numa_info[MAX_NODES]; - static void parse_numa_node(MachineState *ms, NumaNodeOptions *node, Error **errp) @@ -68,11 +64,12 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node, uint16List *cpus = NULL; MachineClass *mc = MACHINE_GET_CLASS(ms); unsigned int max_cpus = ms->smp.max_cpus; + NodeInfo *numa_info = ms->numa_state->nodes; if (node->has_nodeid) { nodenr = node->nodeid; } else { - nodenr = nb_numa_nodes; + nodenr = ms->numa_state->num_nodes; } if (nodenr >= MAX_NODES) { @@ -138,14 +135,16 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node, } numa_info[nodenr].present = true; max_numa_nodeid = MAX(max_numa_nodeid, nodenr + 1); - nb_numa_nodes++; + ms->numa_state->num_nodes++; } -static void parse_numa_distance(NumaDistOptions *dist, Error **errp) +static +void parse_numa_distance(MachineState *ms, NumaDistOptions *dist, Error **errp) { uint16_t src = dist->src; uint16_t dst = dist->dst; uint8_t val = dist->val; + NodeInfo *numa_info = ms->numa_state->nodes; if (src >= MAX_NODES || dst >= MAX_NODES) { error_setg(errp, "Parameter '%s' expects an integer between 0 and %d", @@ -173,12 +172,18 @@ static void parse_numa_distance(NumaDistOptions *dist, Error **errp) } numa_info[src].distance[dst] = val; - have_numa_distance = true; + ms->numa_state->have_numa_distance = true; } void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp) { Error *err = NULL; + MachineClass *mc = MACHINE_GET_CLASS(ms); + + if (!mc->numa_mem_supported) { + error_setg(errp, "NUMA is not supported by this machine-type"); + goto end; + } switch (object->type) { case NUMA_OPTIONS_TYPE_NODE: @@ -188,7 +193,7 @@ void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp) } break; case NUMA_OPTIONS_TYPE_DIST: - parse_numa_distance(&object->u.dist, &err); + parse_numa_distance(ms, &object->u.dist, &err); if (err) { goto end; } @@ -198,7 +203,7 @@ void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp) error_setg(&err, "Missing mandatory node-id property"); goto end; } - if (!numa_info[object->u.cpu.node_id].present) { + if (!ms->numa_state->nodes[object->u.cpu.node_id].present) { error_setg(&err, "Invalid node-id=%" PRId64 ", NUMA node must be " "defined with -numa node,nodeid=ID before it's used with " "-numa cpu,node-id=ID", object->u.cpu.node_id); @@ -253,10 +258,12 @@ end: * distance from a node to itself is always NUMA_DISTANCE_MIN, * so providing it is never necessary. */ -static void validate_numa_distance(void) +static void validate_numa_distance(MachineState *ms) { int src, dst; bool is_asymmetrical = false; + int nb_numa_nodes = ms->numa_state->num_nodes; + NodeInfo *numa_info = ms->numa_state->nodes; for (src = 0; src < nb_numa_nodes; src++) { for (dst = src; dst < nb_numa_nodes; dst++) { @@ -294,17 +301,18 @@ static void validate_numa_distance(void) } } -static void complete_init_numa_distance(void) +static void complete_init_numa_distance(MachineState *ms) { int src, dst; + NodeInfo *numa_info = ms->numa_state->nodes; /* Fixup NUMA distance by symmetric policy because if it is an * asymmetric distance table, it should be a complete table and * there would not be any missing distance except local node, which * is verified by validate_numa_distance above. */ - for (src = 0; src < nb_numa_nodes; src++) { - for (dst = 0; dst < nb_numa_nodes; dst++) { + for (src = 0; src < ms->numa_state->num_nodes; src++) { + for (dst = 0; dst < ms->numa_state->num_nodes; dst++) { if (numa_info[src].distance[dst] == 0) { if (src == dst) { numa_info[src].distance[dst] = NUMA_DISTANCE_MIN; @@ -356,6 +364,7 @@ void numa_complete_configuration(MachineState *ms) { int i; MachineClass *mc = MACHINE_GET_CLASS(ms); + NodeInfo *numa_info = ms->numa_state->nodes; /* * If memory hotplug is enabled (slots > 0) but without '-numa' @@ -370,7 +379,7 @@ void numa_complete_configuration(MachineState *ms) * * Enable NUMA implicitly by adding a new NUMA node automatically. */ - if (ms->ram_slots > 0 && nb_numa_nodes == 0 && + if (ms->ram_slots > 0 && ms->numa_state->num_nodes == 0 && mc->auto_enable_numa_with_memhp) { NumaNodeOptions node = { }; parse_numa_node(ms, &node, &error_abort); @@ -388,26 +397,27 @@ void numa_complete_configuration(MachineState *ms) } /* This must be always true if all nodes are present: */ - assert(nb_numa_nodes == max_numa_nodeid); + assert(ms->numa_state->num_nodes == max_numa_nodeid); - if (nb_numa_nodes > 0) { + if (ms->numa_state->num_nodes > 0) { uint64_t numa_total; - if (nb_numa_nodes > MAX_NODES) { - nb_numa_nodes = MAX_NODES; + if (ms->numa_state->num_nodes > MAX_NODES) { + ms->numa_state->num_nodes = MAX_NODES; } /* If no memory size is given for any node, assume the default case * and distribute the available memory equally across all nodes */ - for (i = 0; i < nb_numa_nodes; i++) { + for (i = 0; i < ms->numa_state->num_nodes; i++) { if (numa_info[i].node_mem != 0) { break; } } - if (i == nb_numa_nodes) { + if (i == ms->numa_state->num_nodes) { assert(mc->numa_auto_assign_ram); - mc->numa_auto_assign_ram(mc, numa_info, nb_numa_nodes, ram_size); + mc->numa_auto_assign_ram(mc, numa_info, + ms->numa_state->num_nodes, ram_size); if (!qtest_enabled()) { warn_report("Default splitting of RAM between nodes is deprecated," " Use '-numa node,memdev' to explictly define RAM" @@ -416,7 +426,7 @@ void numa_complete_configuration(MachineState *ms) } numa_total = 0; - for (i = 0; i < nb_numa_nodes; i++) { + for (i = 0; i < ms->numa_state->num_nodes; i++) { numa_total += numa_info[i].node_mem; } if (numa_total != ram_size) { @@ -438,12 +448,12 @@ void numa_complete_configuration(MachineState *ms) * asymmetric. In this case, the distances for both directions * of all node pairs are required. */ - if (have_numa_distance) { + if (ms->numa_state->have_numa_distance) { /* Validate enough NUMA distance information was provided. */ - validate_numa_distance(); + validate_numa_distance(ms); /* Validation succeeded, now fill in any missing distances. */ - complete_init_numa_distance(); + complete_init_numa_distance(ms); } } } @@ -510,16 +520,18 @@ void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner, { uint64_t addr = 0; int i; + MachineState *ms = MACHINE(qdev_get_machine()); - if (nb_numa_nodes == 0 || !have_memdevs) { + if (ms->numa_state == NULL || + ms->numa_state->num_nodes == 0 || !have_memdevs) { allocate_system_memory_nonnuma(mr, owner, name, ram_size); return; } memory_region_init(mr, owner, name, ram_size); - for (i = 0; i < nb_numa_nodes; i++) { - uint64_t size = numa_info[i].node_mem; - HostMemoryBackend *backend = numa_info[i].node_memdev; + for (i = 0; i < ms->numa_state->num_nodes; i++) { + uint64_t size = ms->numa_state->nodes[i].node_mem; + HostMemoryBackend *backend = ms->numa_state->nodes[i].node_memdev; if (!backend) { continue; } @@ -575,17 +587,17 @@ static void numa_stat_memory_devices(NumaNodeMem node_mem[]) qapi_free_MemoryDeviceInfoList(info_list); } -void query_numa_node_mem(NumaNodeMem node_mem[]) +void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms) { int i; - if (nb_numa_nodes <= 0) { + if (ms->numa_state == NULL || ms->numa_state->num_nodes <= 0) { return; } numa_stat_memory_devices(node_mem); - for (i = 0; i < nb_numa_nodes; i++) { - node_mem[i].node_mem += numa_info[i].node_mem; + for (i = 0; i < ms->numa_state->num_nodes; i++) { + node_mem[i].node_mem += ms->numa_state->nodes[i].node_mem; } } diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index 0f11d55b14..5a4066383b 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -38,6 +38,7 @@ common-obj-$(CONFIG_RASPI) += bcm2835_fb.o common-obj-$(CONFIG_SM501) += sm501.o common-obj-$(CONFIG_TCX) += tcx.o common-obj-$(CONFIG_CG3) += cg3.o +common-obj-$(CONFIG_NEXTCUBE) += next-fb.o obj-$(CONFIG_VGA) += vga.o diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c new file mode 100644 index 0000000000..2b726a10f8 --- /dev/null +++ b/hw/display/next-fb.c @@ -0,0 +1,146 @@ +/* + * NeXT Cube/Station Framebuffer Emulation + * + * Copyright (c) 2011 Bryce Lanham + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "ui/console.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/display/framebuffer.h" +#include "ui/pixel_ops.h" +#include "hw/m68k/next-cube.h" + +#define NEXTFB(obj) OBJECT_CHECK(NeXTFbState, (obj), TYPE_NEXTFB) + +struct NeXTFbState { + SysBusDevice parent_obj; + + MemoryRegion fb_mr; + MemoryRegionSection fbsection; + QemuConsole *con; + + uint32_t cols; + uint32_t rows; + int invalidate; +}; +typedef struct NeXTFbState NeXTFbState; + +static void nextfb_draw_line(void *opaque, uint8_t *d, const uint8_t *s, + int width, int pitch) +{ + NeXTFbState *nfbstate = NEXTFB(opaque); + static const uint32_t pal[4] = { + 0xFFFFFFFF, 0xFFAAAAAA, 0xFF555555, 0xFF000000 + }; + uint32_t *buf = (uint32_t *)d; + int i = 0; + + for (i = 0; i < nfbstate->cols / 4; i++) { + int j = i * 4; + uint8_t src = s[i]; + buf[j + 3] = pal[src & 0x3]; + src >>= 2; + buf[j + 2] = pal[src & 0x3]; + src >>= 2; + buf[j + 1] = pal[src & 0x3]; + src >>= 2; + buf[j + 0] = pal[src & 0x3]; + } +} + +static void nextfb_update(void *opaque) +{ + NeXTFbState *s = NEXTFB(opaque); + int dest_width = 4; + int src_width; + int first = 0; + int last = 0; + DisplaySurface *surface = qemu_console_surface(s->con); + + src_width = s->cols / 4 + 8; + dest_width = s->cols * 4; + + if (s->invalidate) { + framebuffer_update_memory_section(&s->fbsection, &s->fb_mr, 0, + s->cols, src_width); + s->invalidate = 0; + } + + framebuffer_update_display(surface, &s->fbsection, s->cols, s->rows, + src_width, dest_width, 0, 1, nextfb_draw_line, + s, &first, &last); + + dpy_gfx_update(s->con, 0, 0, s->cols, s->rows); +} + +static void nextfb_invalidate(void *opaque) +{ + NeXTFbState *s = NEXTFB(opaque); + s->invalidate = 1; +} + +static const GraphicHwOps nextfb_ops = { + .invalidate = nextfb_invalidate, + .gfx_update = nextfb_update, +}; + +static void nextfb_realize(DeviceState *dev, Error **errp) +{ + NeXTFbState *s = NEXTFB(dev); + + memory_region_init_ram(&s->fb_mr, OBJECT(dev), "next-video", 0x1CB100, + &error_fatal); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->fb_mr); + + s->invalidate = 1; + s->cols = 1120; + s->rows = 832; + + s->con = graphic_console_init(dev, 0, &nextfb_ops, s); + qemu_console_resize(s->con, s->cols, s->rows); +} + +static void nextfb_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + dc->realize = nextfb_realize; + + /* Note: This device does not any state that we have to reset or migrate */ +} + +static const TypeInfo nextfb_info = { + .name = TYPE_NEXTFB, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NeXTFbState), + .class_init = nextfb_class_init, +}; + +static void nextfb_register_types(void) +{ + type_register_static(&nextfb_info); +} + +type_init(nextfb_register_types) diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index d176df6d44..a254275b64 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -566,14 +566,14 @@ static void xilinx_axidma_init(Object *obj) XilinxAXIDMA *s = XILINX_AXI_DMA(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev), - TYPE_XILINX_AXI_DMA_DATA_STREAM); - object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev), - TYPE_XILINX_AXI_DMA_CONTROL_STREAM); - object_property_add_child(OBJECT(s), "axistream-connected-target", - (Object *)&s->rx_data_dev, &error_abort); - object_property_add_child(OBJECT(s), "axistream-control-connected-target", - (Object *)&s->rx_control_dev, &error_abort); + object_initialize_child(OBJECT(s), "axistream-connected-target", + &s->rx_data_dev, sizeof(s->rx_data_dev), + TYPE_XILINX_AXI_DMA_DATA_STREAM, &error_abort, + NULL); + object_initialize_child(OBJECT(s), "axistream-control-connected-target", + &s->rx_control_dev, sizeof(s->rx_control_dev), + TYPE_XILINX_AXI_DMA_CONTROL_STREAM, &error_abort, + NULL); sysbus_init_irq(sbd, &s->streams[0].irq); sysbus_init_irq(sbd, &s->streams[1].irq); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 034e413fd0..e54e571a75 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2694,9 +2694,9 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) if (pcms->numa_nodes) { acpi_add_table(table_offsets, tables_blob); build_srat(tables_blob, tables->linker, machine); - if (have_numa_distance) { + if (machine->numa_state->have_numa_distance) { acpi_add_table(table_offsets, tables_blob); - build_slit(tables_blob, tables->linker); + build_slit(tables_blob, tables->linker, machine); } } if (acpi_get_mcfg(&mcfg)) { diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 80c133a724..2c59b6894b 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -41,6 +41,9 @@ typedef struct KVMClockState { uint64_t clock; bool clock_valid; + /* whether the 'clock' value was obtained in the 'paused' state */ + bool runstate_paused; + /* whether machine type supports reliable KVM_GET_CLOCK */ bool mach_use_reliable_get_clock; @@ -202,6 +205,8 @@ static void kvmclock_vm_state_change(void *opaque, int running, return; } + s->runstate_paused = runstate_check(RUN_STATE_PAUSED); + kvm_synchronize_all_tsc(); kvm_update_clock(s); @@ -260,9 +265,9 @@ static int kvmclock_pre_load(void *opaque) } /* - * When migrating, read the clock just before migration, - * so that the guest clock counts during the events - * between: + * When migrating a running guest, read the clock just + * before migration, so that the guest clock counts + * during the events between: * * * vm_stop() * * @@ -277,7 +282,9 @@ static int kvmclock_pre_save(void *opaque) { KVMClockState *s = opaque; - kvm_update_clock(s); + if (!s->runstate_paused) { + kvm_update_clock(s); + } return 0; } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index c14ed86439..bad866fe44 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1002,6 +1002,8 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms) int i; const CPUArchIdList *cpus; MachineClass *mc = MACHINE_GET_CLASS(pcms); + MachineState *ms = MACHINE(pcms); + int nb_numa_nodes = ms->numa_state->num_nodes; fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus); @@ -1044,7 +1046,7 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms) } for (i = 0; i < nb_numa_nodes; i++) { numa_fw_cfg[pcms->apic_id_limit + 1 + i] = - cpu_to_le64(numa_info[i].node_mem); + cpu_to_le64(ms->numa_state->nodes[i].node_mem); } fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg, (1 + pcms->apic_id_limit + nb_numa_nodes) * @@ -1774,13 +1776,14 @@ void pc_machine_done(Notifier *notifier, void *data) void pc_guest_info_init(PCMachineState *pcms) { int i; + MachineState *ms = MACHINE(pcms); pcms->apic_xrupt_override = kvm_allows_irq0_override(); - pcms->numa_nodes = nb_numa_nodes; + pcms->numa_nodes = ms->numa_state->num_nodes; pcms->node_mem = g_malloc0(pcms->numa_nodes * sizeof *pcms->node_mem); - for (i = 0; i < nb_numa_nodes; i++) { - pcms->node_mem[i] = numa_info[i].node_mem; + for (i = 0; i < ms->numa_state->num_nodes; i++) { + pcms->node_mem[i] = ms->numa_state->nodes[i].node_mem; } pcms->machine_done.notify = pc_machine_done; @@ -2418,6 +2421,14 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev, int max_socket = (ms->smp.max_cpus - 1) / smp_threads / smp_cores / pcms->smp_dies; + /* + * die-id was optional in QEMU 4.0 and older, so keep it optional + * if there's only one die per socket. + */ + if (cpu->die_id < 0 && pcms->smp_dies == 1) { + cpu->die_id = 0; + } + if (cpu->socket_id < 0) { error_setg(errp, "CPU socket-id is not set"); return; @@ -2425,9 +2436,13 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev, error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u", cpu->socket_id, max_socket); return; + } + if (cpu->die_id < 0) { + error_setg(errp, "CPU die-id is not set"); + return; } else if (cpu->die_id > pcms->smp_dies - 1) { error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u", - cpu->die_id, max_socket); + cpu->die_id, pcms->smp_dies - 1); return; } if (cpu->core_id < 0) { @@ -2869,7 +2884,7 @@ static int64_t pc_get_default_cpu_node_id(const MachineState *ms, int idx) x86_topo_ids_from_apicid(ms->possible_cpus->cpus[idx].arch_id, pcms->smp_dies, ms->smp.cores, ms->smp.threads, &topo); - return topo.pkg_id % nb_numa_nodes; + return topo.pkg_id % ms->numa_state->num_nodes; } static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms) @@ -2901,8 +2916,10 @@ static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms) ms->smp.threads, &topo); ms->possible_cpus->cpus[i].props.has_socket_id = true; ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id; - ms->possible_cpus->cpus[i].props.has_die_id = true; - ms->possible_cpus->cpus[i].props.die_id = topo.die_id; + if (pcms->smp_dies > 1) { + ms->possible_cpus->cpus[i].props.has_die_id = true; + ms->possible_cpus->cpus[i].props.die_id = topo.die_id; + } ms->possible_cpus->cpus[i].props.has_core_id = true; ms->possible_cpus->cpus[i].props.core_id = topo.core_id; ms->possible_cpus->cpus[i].props.has_thread_id = true; diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c index 012ab90396..41ad91ad53 100644 --- a/hw/i386/vmmouse.c +++ b/hw/i386/vmmouse.c @@ -258,6 +258,7 @@ static void vmmouse_reset(DeviceState *d) VMMouseState *s = VMMOUSE(d); s->queue_size = VMMOUSE_QUEUE_SIZE; + s->nb_queue = 0; vmmouse_disable(s); } diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 62ab8b7273..8e93e51e81 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -21,6 +21,7 @@ #include "hw/qdev-properties.h" #include "target/arm/cpu.h" #include "exec/exec-all.h" +#include "exec/memop.h" #include "qemu/log.h" #include "qemu/module.h" #include "trace.h" @@ -2348,7 +2349,8 @@ static MemTxResult nvic_sysreg_ns_write(void *opaque, hwaddr addr, if (attrs.secure) { /* S accesses to the alias act like NS accesses to the real region */ attrs.secure = 0; - return memory_region_dispatch_write(mr, addr, value, size, attrs); + return memory_region_dispatch_write(mr, addr, value, + size_memop(size) | MO_TE, attrs); } else { /* NS attrs are RAZ/WI for privileged, and BusFault for user */ if (attrs.user) { @@ -2367,7 +2369,8 @@ static MemTxResult nvic_sysreg_ns_read(void *opaque, hwaddr addr, if (attrs.secure) { /* S accesses to the alias act like NS accesses to the real region */ attrs.secure = 0; - return memory_region_dispatch_read(mr, addr, data, size, attrs); + return memory_region_dispatch_read(mr, addr, data, + size_memop(size) | MO_TE, attrs); } else { /* NS attrs are RAZ/WI for privileged, and BusFault for user */ if (attrs.user) { @@ -2393,7 +2396,8 @@ static MemTxResult nvic_systick_write(void *opaque, hwaddr addr, /* Direct the access to the correct systick */ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0); - return memory_region_dispatch_write(mr, addr, value, size, attrs); + return memory_region_dispatch_write(mr, addr, value, + size_memop(size) | MO_TE, attrs); } static MemTxResult nvic_systick_read(void *opaque, hwaddr addr, @@ -2405,7 +2409,8 @@ static MemTxResult nvic_systick_read(void *opaque, hwaddr addr, /* Direct the access to the correct systick */ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0); - return memory_region_dispatch_read(mr, addr, data, size, attrs); + return memory_region_dispatch_read(mr, addr, data, size_memop(size) | MO_TE, + attrs); } static const MemoryRegionOps nvic_systick_ops = { diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig index 49ef0b3f6d..a74fac5abd 100644 --- a/hw/m68k/Kconfig +++ b/hw/m68k/Kconfig @@ -7,3 +7,8 @@ config MCF5208 bool select COLDFIRE select PTIMER + +config NEXTCUBE + bool + select FRAMEBUFFER + select ESCC diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs index 482f8477b4..f25854730d 100644 --- a/hw/m68k/Makefile.objs +++ b/hw/m68k/Makefile.objs @@ -1,2 +1,3 @@ obj-$(CONFIG_AN5206) += an5206.o mcf5206.o obj-$(CONFIG_MCF5208) += mcf5208.o mcf_intc.o +obj-$(CONFIG_NEXTCUBE) += next-kbd.o next-cube.o diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c new file mode 100644 index 0000000000..9a4a7328f9 --- /dev/null +++ b/hw/m68k/next-cube.c @@ -0,0 +1,978 @@ +/* + * NeXT Cube System Driver + * + * Copyright (c) 2011 Bryce Lanham + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/hwaddr.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "hw/irq.h" +#include "hw/m68k/next-cube.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/scsi/esp.h" +#include "hw/sysbus.h" +#include "hw/char/escc.h" /* ZILOG 8530 Serial Emulation */ +#include "hw/block/fdc.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" +#include "ui/console.h" +#include "target/m68k/cpu.h" + +/* #define DEBUG_NEXT */ +#ifdef DEBUG_NEXT +#define DPRINTF(fmt, ...) \ + do { printf("NeXT: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) do { } while (0) +#endif + +#define TYPE_NEXT_MACHINE MACHINE_TYPE_NAME("next-cube") +#define NEXT_MACHINE(obj) OBJECT_CHECK(NeXTState, (obj), TYPE_NEXT_MACHINE) + +#define ENTRY 0x0100001e +#define RAM_SIZE 0x4000000 +#define ROM_FILE "Rev_2.5_v66.bin" + +typedef struct next_dma { + uint32_t csr; + + uint32_t saved_next; + uint32_t saved_limit; + uint32_t saved_start; + uint32_t saved_stop; + + uint32_t next; + uint32_t limit; + uint32_t start; + uint32_t stop; + + uint32_t next_initbuf; + uint32_t size; +} next_dma; + +typedef struct { + MachineState parent; + + uint32_t int_mask; + uint32_t int_status; + + uint8_t scsi_csr_1; + uint8_t scsi_csr_2; + next_dma dma[10]; + qemu_irq *scsi_irq; + qemu_irq scsi_dma; + qemu_irq scsi_reset; + qemu_irq *fd_irq; + + uint32_t scr1; + uint32_t scr2; + + uint8_t rtc_ram[32]; +} NeXTState; + +/* Thanks to NeXT forums for this */ +/* +static const uint8_t rtc_ram3[32] = { + 0x94, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x7B, 0x00, + 0x00, 0x00, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x13 +}; +*/ +static const uint8_t rtc_ram2[32] = { + 0x94, 0x0f, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x4b, 0x00, + 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x7e, +}; + +#define SCR2_RTCLK 0x2 +#define SCR2_RTDATA 0x4 +#define SCR2_TOBCD(x) (((x / 10) << 4) + (x % 10)) + +static void nextscr2_write(NeXTState *s, uint32_t val, int size) +{ + static int led; + static int phase; + static uint8_t old_scr2; + static uint8_t rtc_command; + static uint8_t rtc_value; + static uint8_t rtc_status = 0x90; + static uint8_t rtc_return; + uint8_t scr2_2; + + if (size == 4) { + scr2_2 = (val >> 8) & 0xFF; + } else { + scr2_2 = val & 0xFF; + } + + if (val & 0x1) { + DPRINTF("fault!\n"); + led++; + if (led == 10) { + DPRINTF("LED flashing, possible fault!\n"); + led = 0; + } + } + + if (scr2_2 & 0x1) { + /* DPRINTF("RTC %x phase %i\n", scr2_2, phase); */ + if (phase == -1) { + phase = 0; + } + /* If we are in going down clock... do something */ + if (((old_scr2 & SCR2_RTCLK) != (scr2_2 & SCR2_RTCLK)) && + ((scr2_2 & SCR2_RTCLK) == 0)) { + if (phase < 8) { + rtc_command = (rtc_command << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + } + if (phase >= 8 && phase < 16) { + rtc_value = (rtc_value << 1) | ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + + /* if we read RAM register, output RT_DATA bit */ + if (rtc_command <= 0x1F) { + scr2_2 = scr2_2 & (~SCR2_RTDATA); + if (s->rtc_ram[rtc_command] & (0x80 >> (phase - 8))) { + scr2_2 |= SCR2_RTDATA; + } + + rtc_return = (rtc_return << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + } + /* read the status 0x30 */ + if (rtc_command == 0x30) { + scr2_2 = scr2_2 & (~SCR2_RTDATA); + /* for now status = 0x98 (new rtc + FTU) */ + if (rtc_status & (0x80 >> (phase - 8))) { + scr2_2 |= SCR2_RTDATA; + } + + rtc_return = (rtc_return << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + } + /* read the status 0x31 */ + if (rtc_command == 0x31) { + scr2_2 = scr2_2 & (~SCR2_RTDATA); + /* for now 0x00 */ + if (0x00 & (0x80 >> (phase - 8))) { + scr2_2 |= SCR2_RTDATA; + } + rtc_return = (rtc_return << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + } + + if ((rtc_command >= 0x20) && (rtc_command <= 0x2F)) { + scr2_2 = scr2_2 & (~SCR2_RTDATA); + /* for now 0x00 */ + time_t time_h = time(NULL); + struct tm *info = localtime(&time_h); + int ret = 0; + + switch (rtc_command) { + case 0x20: + ret = SCR2_TOBCD(info->tm_sec); + break; + case 0x21: + ret = SCR2_TOBCD(info->tm_min); + break; + case 0x22: + ret = SCR2_TOBCD(info->tm_hour); + break; + case 0x24: + ret = SCR2_TOBCD(info->tm_mday); + break; + case 0x25: + ret = SCR2_TOBCD((info->tm_mon + 1)); + break; + case 0x26: + ret = SCR2_TOBCD((info->tm_year - 100)); + break; + + } + + if (ret & (0x80 >> (phase - 8))) { + scr2_2 |= SCR2_RTDATA; + } + rtc_return = (rtc_return << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + } + + } + + phase++; + if (phase == 16) { + if (rtc_command >= 0x80 && rtc_command <= 0x9F) { + s->rtc_ram[rtc_command - 0x80] = rtc_value; + } + /* write to x30 register */ + if (rtc_command == 0xB1) { + /* clear FTU */ + if (rtc_value & 0x04) { + rtc_status = rtc_status & (~0x18); + s->int_status = s->int_status & (~0x04); + } + } + } + } + } else { + /* else end or abort */ + phase = -1; + rtc_command = 0; + rtc_value = 0; + } + s->scr2 = val & 0xFFFF00FF; + s->scr2 |= scr2_2 << 8; + old_scr2 = scr2_2; +} + +static uint32_t mmio_readb(NeXTState *s, hwaddr addr) +{ + switch (addr) { + case 0xc000: + return (s->scr1 >> 24) & 0xFF; + case 0xc001: + return (s->scr1 >> 16) & 0xFF; + case 0xc002: + return (s->scr1 >> 8) & 0xFF; + case 0xc003: + return (s->scr1 >> 0) & 0xFF; + + case 0xd000: + return (s->scr2 >> 24) & 0xFF; + case 0xd001: + return (s->scr2 >> 16) & 0xFF; + case 0xd002: + return (s->scr2 >> 8) & 0xFF; + case 0xd003: + return (s->scr2 >> 0) & 0xFF; + case 0x14020: + DPRINTF("MMIO Read 0x4020\n"); + return 0x7f; + + default: + DPRINTF("MMIO Read B @ %"HWADDR_PRIx"\n", addr); + return 0x0; + } +} + +static uint32_t mmio_readw(NeXTState *s, hwaddr addr) +{ + switch (addr) { + default: + DPRINTF("MMIO Read W @ %"HWADDR_PRIx"\n", addr); + return 0x0; + } +} + +static uint32_t mmio_readl(NeXTState *s, hwaddr addr) +{ + switch (addr) { + case 0x7000: + /* DPRINTF("Read INT status: %x\n", s->int_status); */ + return s->int_status; + + case 0x7800: + DPRINTF("MMIO Read INT mask: %x\n", s->int_mask); + return s->int_mask; + + case 0xc000: + return s->scr1; + + case 0xd000: + return s->scr2; + + default: + DPRINTF("MMIO Read L @ %"HWADDR_PRIx"\n", addr); + return 0x0; + } +} + +static void mmio_writeb(NeXTState *s, hwaddr addr, uint32_t val) +{ + switch (addr) { + case 0xd003: + nextscr2_write(s, val, 1); + break; + default: + DPRINTF("MMIO Write B @ %x with %x\n", (unsigned int)addr, val); + } + +} + +static void mmio_writew(NeXTState *s, hwaddr addr, uint32_t val) +{ + DPRINTF("MMIO Write W\n"); +} + +static void mmio_writel(NeXTState *s, hwaddr addr, uint32_t val) +{ + switch (addr) { + case 0x7000: + DPRINTF("INT Status old: %x new: %x\n", s->int_status, val); + s->int_status = val; + break; + case 0x7800: + DPRINTF("INT Mask old: %x new: %x\n", s->int_mask, val); + s->int_mask = val; + break; + case 0xc000: + DPRINTF("SCR1 Write: %x\n", val); + break; + case 0xd000: + nextscr2_write(s, val, 4); + break; + + default: + DPRINTF("MMIO Write l @ %x with %x\n", (unsigned int)addr, val); + } +} + +static uint64_t mmio_readfn(void *opaque, hwaddr addr, unsigned size) +{ + NeXTState *ns = NEXT_MACHINE(opaque); + + switch (size) { + case 1: + return mmio_readb(ns, addr); + case 2: + return mmio_readw(ns, addr); + case 4: + return mmio_readl(ns, addr); + default: + g_assert_not_reached(); + } +} + +static void mmio_writefn(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + NeXTState *ns = NEXT_MACHINE(opaque); + + switch (size) { + case 1: + mmio_writeb(ns, addr, value); + break; + case 2: + mmio_writew(ns, addr, value); + break; + case 4: + mmio_writel(ns, addr, value); + break; + default: + g_assert_not_reached(); + } +} + +static const MemoryRegionOps mmio_ops = { + .read = mmio_readfn, + .write = mmio_writefn, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static uint32_t scr_readb(NeXTState *s, hwaddr addr) +{ + switch (addr) { + case 0x14108: + DPRINTF("FD read @ %x\n", (unsigned int)addr); + return 0x40 | 0x04 | 0x2 | 0x1; + case 0x14020: + DPRINTF("SCSI 4020 STATUS READ %X\n", s->scsi_csr_1); + return s->scsi_csr_1; + + case 0x14021: + DPRINTF("SCSI 4021 STATUS READ %X\n", s->scsi_csr_2); + return 0x40; + + /* + * These 4 registers are the hardware timer, not sure which register + * is the latch instead of data, but no problems so far + */ + case 0x1a000: + return 0xff & (clock() >> 24); + case 0x1a001: + return 0xff & (clock() >> 16); + case 0x1a002: + return 0xff & (clock() >> 8); + case 0x1a003: + /* Hack: We need to have this change consistently to make it work */ + return 0xFF & clock(); + + default: + DPRINTF("BMAP Read B @ %x\n", (unsigned int)addr); + return 0; + } +} + +static uint32_t scr_readw(NeXTState *s, hwaddr addr) +{ + DPRINTF("BMAP Read W @ %x\n", (unsigned int)addr); + return 0; +} + +static uint32_t scr_readl(NeXTState *s, hwaddr addr) +{ + DPRINTF("BMAP Read L @ %x\n", (unsigned int)addr); + return 0; +} + +#define SCSICSR_ENABLE 0x01 +#define SCSICSR_RESET 0x02 /* reset scsi dma */ +#define SCSICSR_FIFOFL 0x04 +#define SCSICSR_DMADIR 0x08 /* if set, scsi to mem */ +#define SCSICSR_CPUDMA 0x10 /* if set, dma enabled */ +#define SCSICSR_INTMASK 0x20 /* if set, interrupt enabled */ + +static void scr_writeb(NeXTState *s, hwaddr addr, uint32_t value) +{ + switch (addr) { + case 0x14108: + DPRINTF("FDCSR Write: %x\n", value); + + if (value == 0x0) { + /* qemu_irq_raise(s->fd_irq[0]); */ + } + break; + case 0x14020: /* SCSI Control Register */ + if (value & SCSICSR_FIFOFL) { + DPRINTF("SCSICSR FIFO Flush\n"); + /* will have to add another irq to the esp if this is needed */ + /* esp_puflush_fifo(esp_g); */ + /* qemu_irq_pulse(s->scsi_dma); */ + } + + if (value & SCSICSR_ENABLE) { + DPRINTF("SCSICSR Enable\n"); + /* + * qemu_irq_raise(s->scsi_dma); + * s->scsi_csr_1 = 0xc0; + * s->scsi_csr_1 |= 0x1; + * qemu_irq_pulse(s->scsi_dma); + */ + } + /* + * else + * s->scsi_csr_1 &= ~SCSICSR_ENABLE; + */ + + if (value & SCSICSR_RESET) { + DPRINTF("SCSICSR Reset\n"); + /* I think this should set DMADIR. CPUDMA and INTMASK to 0 */ + /* qemu_irq_raise(s->scsi_reset); */ + /* s->scsi_csr_1 &= ~(SCSICSR_INTMASK |0x80|0x1); */ + + } + if (value & SCSICSR_DMADIR) { + DPRINTF("SCSICSR DMAdir\n"); + } + if (value & SCSICSR_CPUDMA) { + DPRINTF("SCSICSR CPUDMA\n"); + /* qemu_irq_raise(s->scsi_dma); */ + + s->int_status |= 0x4000000; + } else { + s->int_status &= ~(0x4000000); + } + if (value & SCSICSR_INTMASK) { + DPRINTF("SCSICSR INTMASK\n"); + /* + * int_mask &= ~0x1000; + * s->scsi_csr_1 |= value; + * s->scsi_csr_1 &= ~SCSICSR_INTMASK; + * if (s->scsi_queued) { + * s->scsi_queued = 0; + * next_irq(s, NEXT_SCSI_I, level); + * } + */ + } else { + /* int_mask |= 0x1000; */ + } + if (value & 0x80) { + /* int_mask |= 0x1000; */ + /* s->scsi_csr_1 |= 0x80; */ + } + DPRINTF("SCSICSR Write: %x\n", value); + /* s->scsi_csr_1 = value; */ + return; + /* Hardware timer latch - not implemented yet */ + case 0x1a000: + default: + DPRINTF("BMAP Write B @ %x with %x\n", (unsigned int)addr, value); + } +} + +static void scr_writew(NeXTState *s, hwaddr addr, uint32_t value) +{ + DPRINTF("BMAP Write W @ %x with %x\n", (unsigned int)addr, value); +} + +static void scr_writel(NeXTState *s, hwaddr addr, uint32_t value) +{ + DPRINTF("BMAP Write L @ %x with %x\n", (unsigned int)addr, value); +} + +static uint64_t scr_readfn(void *opaque, hwaddr addr, unsigned size) +{ + NeXTState *ns = NEXT_MACHINE(opaque); + + switch (size) { + case 1: + return scr_readb(ns, addr); + case 2: + return scr_readw(ns, addr); + case 4: + return scr_readl(ns, addr); + default: + g_assert_not_reached(); + } +} + +static void scr_writefn(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + NeXTState *ns = NEXT_MACHINE(opaque); + + switch (size) { + case 1: + scr_writeb(ns, addr, value); + break; + case 2: + scr_writew(ns, addr, value); + break; + case 4: + scr_writel(ns, addr, value); + break; + default: + g_assert_not_reached(); + } +} + +static const MemoryRegionOps scr_ops = { + .read = scr_readfn, + .write = scr_writefn, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +#define NEXTDMA_SCSI(x) (0x10 + x) +#define NEXTDMA_FD(x) (0x10 + x) +#define NEXTDMA_ENTX(x) (0x110 + x) +#define NEXTDMA_ENRX(x) (0x150 + x) +#define NEXTDMA_CSR 0x0 +#define NEXTDMA_NEXT 0x4000 +#define NEXTDMA_LIMIT 0x4004 +#define NEXTDMA_START 0x4008 +#define NEXTDMA_STOP 0x400c +#define NEXTDMA_NEXT_INIT 0x4200 +#define NEXTDMA_SIZE 0x4204 + +static void dma_writel(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) +{ + NeXTState *next_state = NEXT_MACHINE(opaque); + + switch (addr) { + case NEXTDMA_ENRX(NEXTDMA_CSR): + if (value & DMA_DEV2M) { + next_state->dma[NEXTDMA_ENRX].csr |= DMA_DEV2M; + } + + if (value & DMA_SETENABLE) { + /* DPRINTF("SCSI DMA ENABLE\n"); */ + next_state->dma[NEXTDMA_ENRX].csr |= DMA_ENABLE; + } + if (value & DMA_SETSUPDATE) { + next_state->dma[NEXTDMA_ENRX].csr |= DMA_SUPDATE; + } + if (value & DMA_CLRCOMPLETE) { + next_state->dma[NEXTDMA_ENRX].csr &= ~DMA_COMPLETE; + } + + if (value & DMA_RESET) { + next_state->dma[NEXTDMA_ENRX].csr &= ~(DMA_COMPLETE | DMA_SUPDATE | + DMA_ENABLE | DMA_DEV2M); + } + /* DPRINTF("RXCSR \tWrite: %x\n",value); */ + break; + case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT): + next_state->dma[NEXTDMA_ENRX].next_initbuf = value; + break; + case NEXTDMA_ENRX(NEXTDMA_NEXT): + next_state->dma[NEXTDMA_ENRX].next = value; + break; + case NEXTDMA_ENRX(NEXTDMA_LIMIT): + next_state->dma[NEXTDMA_ENRX].limit = value; + break; + case NEXTDMA_SCSI(NEXTDMA_CSR): + if (value & DMA_DEV2M) { + next_state->dma[NEXTDMA_SCSI].csr |= DMA_DEV2M; + } + if (value & DMA_SETENABLE) { + /* DPRINTF("SCSI DMA ENABLE\n"); */ + next_state->dma[NEXTDMA_SCSI].csr |= DMA_ENABLE; + } + if (value & DMA_SETSUPDATE) { + next_state->dma[NEXTDMA_SCSI].csr |= DMA_SUPDATE; + } + if (value & DMA_CLRCOMPLETE) { + next_state->dma[NEXTDMA_SCSI].csr &= ~DMA_COMPLETE; + } + + if (value & DMA_RESET) { + next_state->dma[NEXTDMA_SCSI].csr &= ~(DMA_COMPLETE | DMA_SUPDATE | + DMA_ENABLE | DMA_DEV2M); + /* DPRINTF("SCSI DMA RESET\n"); */ + } + /* DPRINTF("RXCSR \tWrite: %x\n",value); */ + break; + + case NEXTDMA_SCSI(NEXTDMA_NEXT): + next_state->dma[NEXTDMA_SCSI].next = value; + break; + + case NEXTDMA_SCSI(NEXTDMA_LIMIT): + next_state->dma[NEXTDMA_SCSI].limit = value; + break; + + case NEXTDMA_SCSI(NEXTDMA_START): + next_state->dma[NEXTDMA_SCSI].start = value; + break; + + case NEXTDMA_SCSI(NEXTDMA_STOP): + next_state->dma[NEXTDMA_SCSI].stop = value; + break; + + case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT): + next_state->dma[NEXTDMA_SCSI].next_initbuf = value; + break; + + default: + DPRINTF("DMA write @ %x w/ %x\n", (unsigned)addr, (unsigned)value); + } +} + +static uint64_t dma_readl(void *opaque, hwaddr addr, unsigned int size) +{ + NeXTState *next_state = NEXT_MACHINE(opaque); + + switch (addr) { + case NEXTDMA_SCSI(NEXTDMA_CSR): + DPRINTF("SCSI DMA CSR READ\n"); + return next_state->dma[NEXTDMA_SCSI].csr; + case NEXTDMA_ENRX(NEXTDMA_CSR): + return next_state->dma[NEXTDMA_ENRX].csr; + case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT): + return next_state->dma[NEXTDMA_ENRX].next_initbuf; + case NEXTDMA_ENRX(NEXTDMA_NEXT): + return next_state->dma[NEXTDMA_ENRX].next; + case NEXTDMA_ENRX(NEXTDMA_LIMIT): + return next_state->dma[NEXTDMA_ENRX].limit; + + case NEXTDMA_SCSI(NEXTDMA_NEXT): + return next_state->dma[NEXTDMA_SCSI].next; + case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT): + return next_state->dma[NEXTDMA_SCSI].next_initbuf; + case NEXTDMA_SCSI(NEXTDMA_LIMIT): + return next_state->dma[NEXTDMA_SCSI].limit; + case NEXTDMA_SCSI(NEXTDMA_START): + return next_state->dma[NEXTDMA_SCSI].start; + case NEXTDMA_SCSI(NEXTDMA_STOP): + return next_state->dma[NEXTDMA_SCSI].stop; + + default: + DPRINTF("DMA read @ %x\n", (unsigned int)addr); + return 0; + } + + /* + * once the csr's are done, subtract 0x3FEC from the addr, and that will + * normalize the upper registers + */ +} + +static const MemoryRegionOps dma_ops = { + .read = dma_readl, + .write = dma_writel, + .impl.min_access_size = 4, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +/* + * TODO: set the shift numbers as values in the enum, so the first switch + * will not be needed + */ +void next_irq(void *opaque, int number, int level) +{ + M68kCPU *cpu = opaque; + int shift = 0; + NeXTState *ns = NEXT_MACHINE(qdev_get_machine()); + + /* first switch sets interupt status */ + /* DPRINTF("IRQ %i\n",number); */ + switch (number) { + /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */ + case NEXT_FD_I: + shift = 7;; + break; + case NEXT_KBD_I: + shift = 3; + break; + case NEXT_PWR_I: + shift = 2; + break; + case NEXT_ENRX_I: + shift = 9; + break; + case NEXT_ENTX_I: + shift = 10; + break; + case NEXT_SCSI_I: + shift = 12; + break; + case NEXT_CLK_I: + shift = 5; + break; + + /* level 5 - scc (serial) */ + case NEXT_SCC_I: + shift = 17; + break; + + /* level 6 - audio etherrx/tx dma */ + case NEXT_ENTX_DMA_I: + shift = 28; + break; + case NEXT_ENRX_DMA_I: + shift = 27; + break; + case NEXT_SCSI_DMA_I: + shift = 26; + break; + case NEXT_SND_I: + shift = 23; + break; + case NEXT_SCC_DMA_I: + shift = 21; + break; + + } + /* + * this HAS to be wrong, the interrupt handlers in mach and together + * int_status and int_mask and return if there is a hit + */ + if (ns->int_mask & (1 << shift)) { + DPRINTF("%x interrupt masked @ %x\n", 1 << shift, cpu->env.pc); + /* return; */ + } + + /* second switch triggers the correct interrupt */ + if (level) { + ns->int_status |= 1 << shift; + + switch (number) { + /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */ + case NEXT_FD_I: + case NEXT_KBD_I: + case NEXT_PWR_I: + case NEXT_ENRX_I: + case NEXT_ENTX_I: + case NEXT_SCSI_I: + case NEXT_CLK_I: + m68k_set_irq_level(cpu, 3, 27); + break; + + /* level 5 - scc (serial) */ + case NEXT_SCC_I: + m68k_set_irq_level(cpu, 5, 29); + break; + + /* level 6 - audio etherrx/tx dma */ + case NEXT_ENTX_DMA_I: + case NEXT_ENRX_DMA_I: + case NEXT_SCSI_DMA_I: + case NEXT_SND_I: + case NEXT_SCC_DMA_I: + m68k_set_irq_level(cpu, 6, 30); + break; + } + } else { + ns->int_status &= ~(1 << shift); + cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); + } +} + +static void next_serial_irq(void *opaque, int n, int level) +{ + /* DPRINTF("SCC IRQ NUM %i\n",n); */ + if (n) { + next_irq(opaque, NEXT_SCC_DMA_I, level); + } else { + next_irq(opaque, NEXT_SCC_I, level); + } +} + +static void next_escc_init(M68kCPU *cpu) +{ + qemu_irq *ser_irq = qemu_allocate_irqs(next_serial_irq, cpu, 2); + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, TYPE_ESCC); + qdev_prop_set_uint32(dev, "disabled", 0); + qdev_prop_set_uint32(dev, "frequency", 9600 * 384); + qdev_prop_set_uint32(dev, "it_shift", 0); + qdev_prop_set_bit(dev, "bit_swap", true); + qdev_prop_set_chr(dev, "chrB", serial_hd(1)); + qdev_prop_set_chr(dev, "chrA", serial_hd(0)); + qdev_prop_set_uint32(dev, "chnBtype", escc_serial); + qdev_prop_set_uint32(dev, "chnAtype", escc_serial); + qdev_init_nofail(dev); + + s = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(s, 0, ser_irq[0]); + sysbus_connect_irq(s, 1, ser_irq[1]); + sysbus_mmio_map(s, 0, 0x2118000); +} + +static void next_cube_init(MachineState *machine) +{ + M68kCPU *cpu; + CPUM68KState *env; + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *rom = g_new(MemoryRegion, 1); + MemoryRegion *mmiomem = g_new(MemoryRegion, 1); + MemoryRegion *scrmem = g_new(MemoryRegion, 1); + MemoryRegion *dmamem = g_new(MemoryRegion, 1); + MemoryRegion *bmapm1 = g_new(MemoryRegion, 1); + MemoryRegion *bmapm2 = g_new(MemoryRegion, 1); + MemoryRegion *sysmem = get_system_memory(); + NeXTState *ns = NEXT_MACHINE(machine); + DeviceState *dev; + + /* Initialize the cpu core */ + cpu = M68K_CPU(cpu_create(machine->cpu_type)); + if (!cpu) { + error_report("Unable to find m68k CPU definition"); + exit(1); + } + env = &cpu->env; + + /* Initialize CPU registers. */ + env->vbr = 0; + env->sr = 0x2700; + + /* Set internal registers to initial values */ + /* 0x0000XX00 << vital bits */ + ns->scr1 = 0x00011102; + ns->scr2 = 0x00ff0c80; + + /* Load RTC RAM - TODO: provide possibility to load contents from file */ + memcpy(ns->rtc_ram, rtc_ram2, 32); + + /* 64MB RAM starting at 0x04000000 */ + memory_region_allocate_system_memory(ram, NULL, "next.ram", ram_size); + memory_region_add_subregion(sysmem, 0x04000000, ram); + + /* Framebuffer */ + dev = qdev_create(NULL, TYPE_NEXTFB); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0B000000); + + /* MMIO */ + memory_region_init_io(mmiomem, NULL, &mmio_ops, machine, "next.mmio", + 0xD0000); + memory_region_add_subregion(sysmem, 0x02000000, mmiomem); + + /* BMAP memory */ + memory_region_init_ram_shared_nomigrate(bmapm1, NULL, "next.bmapmem", 64, + true, &error_fatal); + memory_region_add_subregion(sysmem, 0x020c0000, bmapm1); + /* The Rev_2.5_v66.bin firmware accesses it at 0x820c0020, too */ + memory_region_init_alias(bmapm2, NULL, "next.bmapmem2", bmapm1, 0x0, 64); + memory_region_add_subregion(sysmem, 0x820c0000, bmapm2); + + /* BMAP IO - acts as a catch-all for now */ + memory_region_init_io(scrmem, NULL, &scr_ops, machine, "next.scr", + 0x20000); + memory_region_add_subregion(sysmem, 0x02100000, scrmem); + + /* KBD */ + dev = qdev_create(NULL, TYPE_NEXTKBD); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0200e000); + + /* Load ROM here */ + if (bios_name == NULL) { + bios_name = ROM_FILE; + } + /* still not sure if the rom should also be mapped at 0x0*/ + memory_region_init_rom(rom, NULL, "next.rom", 0x20000, &error_fatal); + memory_region_add_subregion(sysmem, 0x01000000, rom); + if (load_image_targphys(bios_name, 0x01000000, 0x20000) < 8) { + if (!qtest_enabled()) { + error_report("Failed to load firmware '%s'.", bios_name); + } + } else { + uint8_t *ptr; + /* Initial PC is always at offset 4 in firmware binaries */ + ptr = rom_ptr(0x01000004, 4); + g_assert(ptr != NULL); + env->pc = ldl_p(ptr); + if (env->pc >= 0x01020000) { + error_report("'%s' does not seem to be a valid firmware image.", + bios_name); + exit(1); + } + } + + /* Serial */ + next_escc_init(cpu); + + /* TODO: */ + /* Network */ + /* SCSI */ + + /* DMA */ + memory_region_init_io(dmamem, NULL, &dma_ops, machine, "next.dma", 0x5000); + memory_region_add_subregion(sysmem, 0x02000000, dmamem); +} + +static void next_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "NeXT Cube"; + mc->init = next_cube_init; + mc->default_ram_size = RAM_SIZE; + mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040"); +} + +static const TypeInfo next_typeinfo = { + .name = TYPE_NEXT_MACHINE, + .parent = TYPE_MACHINE, + .class_init = next_machine_class_init, + .instance_size = sizeof(NeXTState), +}; + +static void next_register_type(void) +{ + type_register_static(&next_typeinfo); +} + +type_init(next_register_type) diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c new file mode 100644 index 0000000000..2dff87be15 --- /dev/null +++ b/hw/m68k/next-kbd.c @@ -0,0 +1,291 @@ +/* + * QEMU NeXT Keyboard/Mouse emulation + * + * Copyright (c) 2011 Bryce Lanham + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + * This is admittedly hackish, but works well enough for basic input. Mouse + * support will be added once we can boot something that needs the mouse. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "exec/address-spaces.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/m68k/next-cube.h" +#include "ui/console.h" +#include "sysemu/sysemu.h" +#include "migration/vmstate.h" + +#define NEXTKBD(obj) OBJECT_CHECK(NextKBDState, (obj), TYPE_NEXTKBD) + +/* following defintions from next68k netbsd */ +#define CSR_INT 0x00800000 +#define CSR_DATA 0x00400000 + +#define KD_KEYMASK 0x007f +#define KD_DIRECTION 0x0080 /* pressed or released */ +#define KD_CNTL 0x0100 +#define KD_LSHIFT 0x0200 +#define KD_RSHIFT 0x0400 +#define KD_LCOMM 0x0800 +#define KD_RCOMM 0x1000 +#define KD_LALT 0x2000 +#define KD_RALT 0x4000 +#define KD_VALID 0x8000 /* only set for scancode keys ? */ +#define KD_MODS 0x4f00 + +#define KBD_QUEUE_SIZE 256 + +typedef struct { + uint8_t data[KBD_QUEUE_SIZE]; + int rptr, wptr, count; +} KBDQueue; + + +typedef struct NextKBDState { + SysBusDevice sbd; + MemoryRegion mr; + KBDQueue queue; + uint16_t shift; +} NextKBDState; + +static void queue_code(void *opaque, int code); + +/* lots of magic numbers here */ +static uint32_t kbd_read_byte(void *opaque, hwaddr addr) +{ + switch (addr & 0x3) { + case 0x0: /* 0xe000 */ + return 0x80 | 0x20; + + case 0x1: /* 0xe001 */ + return 0x80 | 0x40 | 0x20 | 0x10; + + case 0x2: /* 0xe002 */ + /* returning 0x40 caused mach to hang */ + return 0x10 | 0x2 | 0x1; + + default: + qemu_log_mask(LOG_UNIMP, "NeXT kbd read byte %"HWADDR_PRIx"\n", addr); + } + + return 0; +} + +static uint32_t kbd_read_word(void *opaque, hwaddr addr) +{ + qemu_log_mask(LOG_UNIMP, "NeXT kbd read word %"HWADDR_PRIx"\n", addr); + return 0; +} + +/* even more magic numbers */ +static uint32_t kbd_read_long(void *opaque, hwaddr addr) +{ + int key = 0; + NextKBDState *s = NEXTKBD(opaque); + KBDQueue *q = &s->queue; + + switch (addr & 0xf) { + case 0x0: /* 0xe000 */ + return 0xA0F09300; + + case 0x8: /* 0xe008 */ + /* get keycode from buffer */ + if (q->count > 0) { + key = q->data[q->rptr]; + if (++q->rptr == KBD_QUEUE_SIZE) { + q->rptr = 0; + } + + q->count--; + + if (s->shift) { + key |= s->shift; + } + + if (key & 0x80) { + return 0; + } else { + return 0x10000000 | KD_VALID | key; + } + } else { + return 0; + } + + default: + qemu_log_mask(LOG_UNIMP, "NeXT kbd read long %"HWADDR_PRIx"\n", addr); + return 0; + } +} + +static uint64_t kbd_readfn(void *opaque, hwaddr addr, unsigned size) +{ + switch (size) { + case 1: + return kbd_read_byte(opaque, addr); + case 2: + return kbd_read_word(opaque, addr); + case 4: + return kbd_read_long(opaque, addr); + default: + g_assert_not_reached(); + } +} + +static void kbd_writefn(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + qemu_log_mask(LOG_UNIMP, "NeXT kbd write: size=%u addr=0x%"HWADDR_PRIx + "val=0x%"PRIx64"\n", size, addr, value); +} + +static const MemoryRegionOps kbd_ops = { + .read = kbd_readfn, + .write = kbd_writefn, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void nextkbd_event(void *opaque, int ch) +{ + /* + * Will want to set vars for caps/num lock + * if (ch & 0x80) -> key release + * there's also e0 escaped scancodes that might need to be handled + */ + queue_code(opaque, ch); +} + +static const unsigned char next_keycodes[128] = { + 0x00, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x50, 0x4F, + 0x4E, 0x1E, 0x1F, 0x20, 0x1D, 0x1C, 0x1B, 0x00, + 0x42, 0x43, 0x44, 0x45, 0x48, 0x47, 0x46, 0x06, + 0x07, 0x08, 0x00, 0x00, 0x2A, 0x00, 0x39, 0x3A, + 0x3B, 0x3C, 0x3D, 0x40, 0x3F, 0x3E, 0x2D, 0x2C, + 0x2B, 0x26, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x37, 0x36, 0x2e, 0x2f, 0x30, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void queue_code(void *opaque, int code) +{ + NextKBDState *s = NEXTKBD(opaque); + KBDQueue *q = &s->queue; + int key = code & KD_KEYMASK; + int release = code & 0x80; + static int ext; + + if (code == 0xE0) { + ext = 1; + } + + if (code == 0x2A || code == 0x1D || code == 0x36) { + if (code == 0x2A) { + s->shift = KD_LSHIFT; + } else if (code == 0x36) { + s->shift = KD_RSHIFT; + ext = 0; + } else if (code == 0x1D && !ext) { + s->shift = KD_LCOMM; + } else if (code == 0x1D && ext) { + ext = 0; + s->shift = KD_RCOMM; + } + return; + } else if (code == (0x2A | 0x80) || code == (0x1D | 0x80) || + code == (0x36 | 0x80)) { + s->shift = 0; + return; + } + + if (q->count >= KBD_QUEUE_SIZE) { + return; + } + + q->data[q->wptr] = next_keycodes[key] | release; + + if (++q->wptr == KBD_QUEUE_SIZE) { + q->wptr = 0; + } + + q->count++; + + /* + * might need to actually trigger the NeXT irq, but as the keyboard works + * at the moment, I'll worry about it later + */ + /* s->update_irq(s->update_arg, 1); */ +} + +static void nextkbd_reset(DeviceState *dev) +{ + NextKBDState *nks = NEXTKBD(dev); + + memset(&nks->queue, 0, sizeof(KBDQueue)); + nks->shift = 0; +} + +static void nextkbd_realize(DeviceState *dev, Error **errp) +{ + NextKBDState *s = NEXTKBD(dev); + + memory_region_init_io(&s->mr, OBJECT(dev), &kbd_ops, s, "next.kbd", 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); + + qemu_add_kbd_event_handler(nextkbd_event, s); +} + +static const VMStateDescription nextkbd_vmstate = { + .name = TYPE_NEXTKBD, + .unmigratable = 1, /* TODO: Implement this when m68k CPU is migratable */ +}; + +static void nextkbd_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + dc->vmsd = &nextkbd_vmstate; + dc->realize = nextkbd_realize; + dc->reset = nextkbd_reset; +} + +static const TypeInfo nextkbd_info = { + .name = TYPE_NEXTKBD, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NextKBDState), + .class_init = nextkbd_class_init, +}; + +static void nextkbd_register_types(void) +{ + type_register_static(&nextkbd_info); +} + +type_init(nextkbd_register_types) diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 7c324a1329..99e2faf01b 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -172,6 +172,8 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp) { PCDIMMDevice *dimm = PC_DIMM(dev); PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); + MachineState *ms = MACHINE(qdev_get_machine()); + int nb_numa_nodes = ms->numa_state->num_nodes; if (!dimm->hostmem) { error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set"); diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index e4aad707fb..a150680966 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -26,57 +26,57 @@ common-obj-$(CONFIG_PUV3) += puv3_pm.o common-obj-$(CONFIG_MACIO) += macio/ -obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o +common-obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o -obj-$(CONFIG_REALVIEW) += arm_sysctl.o -obj-$(CONFIG_NSERIES) += cbus.o -obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o -obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o exynos4210_clk.o exynos4210_rng.o -obj-$(CONFIG_IMX) += imx_ccm.o -obj-$(CONFIG_IMX) += imx31_ccm.o -obj-$(CONFIG_IMX) += imx25_ccm.o -obj-$(CONFIG_IMX) += imx6_ccm.o -obj-$(CONFIG_IMX) += imx6ul_ccm.o +common-obj-$(CONFIG_REALVIEW) += arm_sysctl.o +common-obj-$(CONFIG_NSERIES) += cbus.o +common-obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o +common-obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o exynos4210_clk.o exynos4210_rng.o +common-obj-$(CONFIG_IMX) += imx_ccm.o +common-obj-$(CONFIG_IMX) += imx31_ccm.o +common-obj-$(CONFIG_IMX) += imx25_ccm.o +common-obj-$(CONFIG_IMX) += imx6_ccm.o +common-obj-$(CONFIG_IMX) += imx6ul_ccm.o obj-$(CONFIG_IMX) += imx6_src.o -obj-$(CONFIG_IMX) += imx7_ccm.o -obj-$(CONFIG_IMX) += imx2_wdt.o -obj-$(CONFIG_IMX) += imx7_snvs.o -obj-$(CONFIG_IMX) += imx7_gpr.o -obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o -obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o -obj-$(CONFIG_MAINSTONE) += mst_fpga.o -obj-$(CONFIG_OMAP) += omap_clk.o -obj-$(CONFIG_OMAP) += omap_gpmc.o -obj-$(CONFIG_OMAP) += omap_l4.o -obj-$(CONFIG_OMAP) += omap_sdrc.o -obj-$(CONFIG_OMAP) += omap_tap.o -obj-$(CONFIG_RASPI) += bcm2835_mbox.o -obj-$(CONFIG_RASPI) += bcm2835_property.o -obj-$(CONFIG_RASPI) += bcm2835_rng.o -obj-$(CONFIG_SLAVIO) += slavio_misc.o -obj-$(CONFIG_ZYNQ) += zynq_slcr.o -obj-$(CONFIG_ZYNQ) += zynq-xadc.o -obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o +common-obj-$(CONFIG_IMX) += imx7_ccm.o +common-obj-$(CONFIG_IMX) += imx2_wdt.o +common-obj-$(CONFIG_IMX) += imx7_snvs.o +common-obj-$(CONFIG_IMX) += imx7_gpr.o +common-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o +common-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o +common-obj-$(CONFIG_MAINSTONE) += mst_fpga.o +common-obj-$(CONFIG_OMAP) += omap_clk.o +common-obj-$(CONFIG_OMAP) += omap_gpmc.o +common-obj-$(CONFIG_OMAP) += omap_l4.o +common-obj-$(CONFIG_OMAP) += omap_sdrc.o +common-obj-$(CONFIG_OMAP) += omap_tap.o +common-obj-$(CONFIG_RASPI) += bcm2835_mbox.o +common-obj-$(CONFIG_RASPI) += bcm2835_property.o +common-obj-$(CONFIG_RASPI) += bcm2835_rng.o +common-obj-$(CONFIG_SLAVIO) += slavio_misc.o +common-obj-$(CONFIG_ZYNQ) += zynq_slcr.o +common-obj-$(CONFIG_ZYNQ) += zynq-xadc.o +common-obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o obj-$(CONFIG_MIPS_CPS) += mips_cmgcr.o obj-$(CONFIG_MIPS_CPS) += mips_cpc.o obj-$(CONFIG_MIPS_ITU) += mips_itu.o -obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o -obj-$(CONFIG_MPS2_SCC) += mps2-scc.o +common-obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o +common-obj-$(CONFIG_MPS2_SCC) += mps2-scc.o -obj-$(CONFIG_TZ_MPC) += tz-mpc.o -obj-$(CONFIG_TZ_MSC) += tz-msc.o -obj-$(CONFIG_TZ_PPC) += tz-ppc.o -obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o +common-obj-$(CONFIG_TZ_MPC) += tz-mpc.o +common-obj-$(CONFIG_TZ_MSC) += tz-msc.o +common-obj-$(CONFIG_TZ_PPC) += tz-ppc.o +common-obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o -obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o -obj-$(CONFIG_ARMSSE_CPUID) += armsse-cpuid.o -obj-$(CONFIG_ARMSSE_MHU) += armsse-mhu.o +common-obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o +common-obj-$(CONFIG_ARMSSE_CPUID) += armsse-cpuid.o +common-obj-$(CONFIG_ARMSSE_MHU) += armsse-mhu.o -obj-$(CONFIG_PVPANIC) += pvpanic.o -obj-$(CONFIG_AUX) += auxbus.o -obj-$(CONFIG_ASPEED_SOC) += aspeed_xdma.o -obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o -obj-$(CONFIG_MSF2) += msf2-sysreg.o -obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o +common-obj-$(CONFIG_PVPANIC) += pvpanic.o +common-obj-$(CONFIG_AUX) += auxbus.o +common-obj-$(CONFIG_ASPEED_SOC) += aspeed_xdma.o +common-obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o +common-obj-$(CONFIG_MSF2) += msf2-sysreg.o +common-obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o -obj-$(CONFIG_GRLIB) += grlib_ahb_apb_pnp.o +common-obj-$(CONFIG_GRLIB) += grlib_ahb_apb_pnp.o diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index d8716a1f73..2c8c065401 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -994,15 +994,14 @@ static void xilinx_enet_init(Object *obj) XilinxAXIEnet *s = XILINX_AXI_ENET(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev), - TYPE_XILINX_AXI_ENET_DATA_STREAM); - object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev), - TYPE_XILINX_AXI_ENET_CONTROL_STREAM); - object_property_add_child(OBJECT(s), "axistream-connected-target", - (Object *)&s->rx_data_dev, &error_abort); - object_property_add_child(OBJECT(s), "axistream-control-connected-target", - (Object *)&s->rx_control_dev, &error_abort); - + object_initialize_child(OBJECT(s), "axistream-connected-target", + &s->rx_data_dev, sizeof(s->rx_data_dev), + TYPE_XILINX_AXI_ENET_DATA_STREAM, &error_abort, + NULL); + object_initialize_child(OBJECT(s), "axistream-control-connected-target", + &s->rx_control_dev, sizeof(s->rx_control_dev), + TYPE_XILINX_AXI_ENET_CONTROL_STREAM, &error_abort, + NULL); sysbus_init_irq(sbd, &s->irq); memory_region_init_io(&s->iomem, OBJECT(s), &enet_ops, s, "enet", 0x40000); diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 06a7c018d7..0592818447 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -21,6 +21,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "sysemu/numa.h" +#include "hw/boards.h" #define TYPE_PXB_BUS "pxb-bus" #define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS) @@ -213,9 +214,15 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) PCIBus *bus; const char *dev_name = NULL; Error *local_err = NULL; + MachineState *ms = MACHINE(qdev_get_machine()); + + if (ms->numa_state == NULL) { + error_setg(errp, "NUMA is not supported by this machine-type"); + return; + } if (pxb->numa_node != NUMA_NODE_UNASSIGNED && - pxb->numa_node >= nb_numa_nodes) { + pxb->numa_node >= ms->numa_state->num_nodes) { error_setg(errp, "Illegal numa node %d", pxb->numa_node); return; } diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index d95086fbbd..3f08db7b9e 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -434,9 +434,14 @@ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt) .fdt = fdt, .offset = isa_offset, }; + uint32_t phandle; _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0))); + phandle = qemu_fdt_alloc_phandle(fdt); + assert(phandle > 0); + _FDT((fdt_setprop_cell(fdt, isa_offset, "phandle", phandle))); + /* ISA devices are not necessarily parented to the ISA bus so we * can not use object_child_foreach() */ qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL, @@ -600,9 +605,20 @@ static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon) pnv_psi_pic_print_info(&chip9->psi, mon); } +static bool pnv_match_cpu(const char *default_type, const char *cpu_type) +{ + PowerPCCPUClass *ppc_default = + POWERPC_CPU_CLASS(object_class_by_name(default_type)); + PowerPCCPUClass *ppc = + POWERPC_CPU_CLASS(object_class_by_name(cpu_type)); + + return ppc_default->pvr_match(ppc_default, ppc->pvr); +} + static void pnv_init(MachineState *machine) { PnvMachineState *pnv = PNV_MACHINE(machine); + MachineClass *mc = MACHINE_GET_CLASS(machine); MemoryRegion *ram; char *fw_filename; long fw_size; @@ -662,13 +678,23 @@ static void pnv_init(MachineState *machine) } } + /* + * Check compatibility of the specified CPU with the machine + * default. + */ + if (!pnv_match_cpu(mc->default_cpu_type, machine->cpu_type)) { + error_report("invalid CPU model '%s' for %s machine", + machine->cpu_type, mc->name); + exit(1); + } + /* Create the processor chips */ i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX); chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"), i, machine->cpu_type); if (!object_class_by_name(chip_typename)) { - error_report("invalid CPU model '%.*s' for %s machine", - i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name); + error_report("invalid chip model '%.*s' for %s machine", + i, machine->cpu_type, mc->name); exit(1); } @@ -1346,25 +1372,47 @@ static void pnv_machine_class_props_init(ObjectClass *oc) NULL); } -static void pnv_machine_class_init(ObjectClass *oc, void *data) +static void pnv_machine_power8_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); XICSFabricClass *xic = XICS_FABRIC_CLASS(oc); + + mc->desc = "IBM PowerNV (Non-Virtualized) POWER8"; + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); + + xic->icp_get = pnv_icp_get; + xic->ics_get = pnv_ics_get; + xic->ics_resend = pnv_ics_resend; +} + +static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "IBM PowerNV (Non-Virtualized) POWER9"; + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0"); + + mc->alias = "powernv"; +} + +static void pnv_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); mc->desc = "IBM PowerNV (Non-Virtualized)"; mc->init = pnv_init; mc->reset = pnv_reset; mc->max_cpus = MAX_CPUS; - mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for * storage */ mc->no_parallel = 1; mc->default_boot_order = NULL; - mc->default_ram_size = 1 * GiB; - xic->icp_get = pnv_icp_get; - xic->ics_get = pnv_ics_get; - xic->ics_resend = pnv_ics_resend; + /* + * RAM defaults to less than 2048 for 32-bit hosts, and large + * enough to fit the maximum initrd size at it's load address + */ + mc->default_ram_size = INITRD_LOAD_ADDR + INITRD_MAX_SIZE; ispc->print_info = pnv_pic_print_info; pnv_machine_class_props_init(oc); @@ -1384,10 +1432,27 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data) .parent = TYPE_PNV9_CHIP, \ } +#define DEFINE_PNV_MACHINE_TYPE(cpu, class_initfn) \ + { \ + .name = MACHINE_TYPE_NAME(cpu), \ + .parent = TYPE_PNV_MACHINE, \ + .instance_size = sizeof(PnvMachineState), \ + .instance_init = pnv_machine_instance_init, \ + .class_init = class_initfn, \ + .interfaces = (InterfaceInfo[]) { \ + { TYPE_XICS_FABRIC }, \ + { TYPE_INTERRUPT_STATS_PROVIDER }, \ + { }, \ + }, \ + } + static const TypeInfo types[] = { + DEFINE_PNV_MACHINE_TYPE("powernv8", pnv_machine_power8_class_init), + DEFINE_PNV_MACHINE_TYPE("powernv9", pnv_machine_power9_class_init), { .name = TYPE_PNV_MACHINE, .parent = TYPE_MACHINE, + .abstract = true, .instance_size = sizeof(PnvMachineState), .instance_init = pnv_machine_instance_init, .class_init = pnv_machine_class_init, diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index 0e31c5786b..67aab98fef 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -106,6 +106,16 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba) case 0x201302a: /* CAPP stuff */ case 0x2013801: /* CAPP stuff */ case 0x2013802: /* CAPP stuff */ + + /* P9 CAPP regs */ + case 0x2010841: + case 0x2010842: + case 0x201082a: + case 0x2010828: + case 0x4010841: + case 0x4010842: + case 0x401082a: + case 0x4010828: return 0; default: return -1; @@ -138,6 +148,16 @@ static bool xscom_write_default(PnvChip *chip, uint32_t pcba, uint64_t val) case 0x2013801: /* CAPP stuff */ case 0x2013802: /* CAPP stuff */ + /* P9 CAPP regs */ + case 0x2010841: + case 0x2010842: + case 0x201082a: + case 0x2010828: + case 0x4010841: + case 0x4010842: + case 0x401082a: + case 0x4010828: + /* P8 PRD registers */ case PRD_P8_IPOLL_REG_MASK: case PRD_P8_IPOLL_REG_STATUS: diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index baedadf20b..222a325056 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -336,7 +336,7 @@ static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr) return ret; } - if (nb_numa_nodes > 1) { + if (ms->numa_state->num_nodes > 1) { ret = spapr_fixup_cpu_numa_dt(fdt, offset, cpu); if (ret < 0) { return ret; @@ -356,11 +356,11 @@ static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr) static hwaddr spapr_node0_size(MachineState *machine) { - if (nb_numa_nodes) { + if (machine->numa_state->num_nodes) { int i; - for (i = 0; i < nb_numa_nodes; ++i) { - if (numa_info[i].node_mem) { - return MIN(pow2floor(numa_info[i].node_mem), + for (i = 0; i < machine->numa_state->num_nodes; ++i) { + if (machine->numa_state->nodes[i].node_mem) { + return MIN(pow2floor(machine->numa_state->nodes[i].node_mem), machine->ram_size); } } @@ -403,12 +403,12 @@ static int spapr_populate_memory(SpaprMachineState *spapr, void *fdt) { MachineState *machine = MACHINE(spapr); hwaddr mem_start, node_size; - int i, nb_nodes = nb_numa_nodes; - NodeInfo *nodes = numa_info; + int i, nb_nodes = machine->numa_state->num_nodes; + NodeInfo *nodes = machine->numa_state->nodes; NodeInfo ramnode; /* No NUMA nodes, assume there is just one node with whole RAM */ - if (!nb_numa_nodes) { + if (!nb_nodes) { nb_nodes = 1; ramnode.node_mem = machine->ram_size; nodes = &ramnode; @@ -559,7 +559,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, _FDT((fdt_setprop(fdt, offset, "ibm,pft-size", pft_size_prop, sizeof(pft_size_prop)))); - if (nb_numa_nodes > 1) { + if (ms->numa_state->num_nodes > 1) { _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu)); } @@ -866,6 +866,7 @@ static int spapr_populate_drmem_v1(SpaprMachineState *spapr, void *fdt, static int spapr_populate_drconf_memory(SpaprMachineState *spapr, void *fdt) { MachineState *machine = MACHINE(spapr); + int nb_numa_nodes = machine->numa_state->num_nodes; int ret, i, offset; uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE; uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)}; @@ -1168,6 +1169,7 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt, static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt) { MachineState *machine = MACHINE(spapr); + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); int chosen; const char *boot_device = machine->boot_order; char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus); @@ -1225,6 +1227,11 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt) _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path)); } + /* We can deal with BAR reallocation just fine, advertise it to the guest */ + if (smc->linux_pci_probe) { + _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0)); + } + spapr_dt_ov5_platform_support(spapr, fdt, chosen); g_free(stdout_path); @@ -1741,7 +1748,7 @@ static void spapr_machine_reset(MachineState *machine) * The final value of spapr->gpu_numa_id is going to be written to * max-associativity-domains in spapr_build_fdt(). */ - spapr->gpu_numa_id = MAX(1, nb_numa_nodes); + spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes); qemu_devices_reset(); /* @@ -1752,7 +1759,7 @@ static void spapr_machine_reset(MachineState *machine) spapr_ovec_cleanup(spapr->ov5_cas); spapr->ov5_cas = spapr_ovec_new(); - ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal); + ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal); } /* @@ -2539,12 +2546,12 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp) return; } - for (i = 0; i < nb_numa_nodes; i++) { - if (numa_info[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) { + for (i = 0; i < machine->numa_state->num_nodes; i++) { + if (machine->numa_state->nodes[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) { error_setg(errp, "Node %d memory size 0x%" PRIx64 " is not aligned to %" PRIu64 " MiB", - i, numa_info[i].node_mem, + i, machine->numa_state->nodes[i].node_mem, SPAPR_MEMORY_BLOCK_SIZE / MiB); return; } @@ -3829,6 +3836,7 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, CPUArchId *core_slot; int index; bool hotplugged = spapr_drc_hotplugged(dev); + int i; core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index); if (!core_slot) { @@ -3862,13 +3870,26 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, core_slot->cpu = OBJECT(dev); if (smc->pre_2_10_has_unused_icps) { - int i; - for (i = 0; i < cc->nr_threads; i++) { cs = CPU(core->threads[i]); pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index); } } + + /* + * Set compatibility mode to match the boot CPU, which was either set + * by the machine reset code or by CAS. + */ + if (hotplugged) { + for (i = 0; i < cc->nr_threads; i++) { + ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } + } } static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, @@ -4178,7 +4199,7 @@ spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index) static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx) { - return idx / ms->smp.cores % nb_numa_nodes; + return idx / ms->smp.cores % ms->numa_state->num_nodes; } static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine) @@ -4470,6 +4491,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) spapr_caps_add_properties(smc, &error_abort); smc->irq = &spapr_irq_dual; smc->dr_phb_enabled = true; + smc->linux_pci_probe = true; } static const TypeInfo spapr_machine_info = { @@ -4529,12 +4551,14 @@ DEFINE_SPAPR_MACHINE(4_2, "4.2", true); */ static void spapr_machine_4_1_class_options(MachineClass *mc) { + SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc); static GlobalProperty compat[] = { /* Only allow 4kiB and 64kiB IOMMU pagesizes */ { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" }, }; spapr_machine_4_2_class_options(mc); + smc->linux_pci_probe = false; compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len); compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index bf47fbdf6f..1d93de8161 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -41,11 +41,6 @@ static void spapr_cpu_reset(void *opaque) * using an RTAS call */ cs->halted = 1; - /* Set compatibility mode to match the boot CPU, which was either set - * by the machine reset code or by CAS. This should never fail. - */ - ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &error_abort); - env->spr[SPR_HIOR] = 0; lpcr = env->spr[SPR_LPCR]; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index e20a946b99..23e4bdb829 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1811,7 +1811,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, spapr_ovec_cleanup(ov5_updates); if (spapr->cas_reboot) { - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + qemu_system_reset_request(SHUTDOWN_CAUSE_SUBSYSTEM_RESET); } return H_SUCCESS; diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index deb0b0c80c..7b71ad7c74 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -280,7 +280,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr, unsigned int irq, max_irqs = 0; SpaprPhbState *phb = NULL; PCIDevice *pdev = NULL; - spapr_pci_msi *msi; + SpaprPciMsi *msi; int *config_addr_key; Error *err = NULL; int i; @@ -328,7 +328,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr, return; } - msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr); + msi = (SpaprPciMsi *) g_hash_table_lookup(phb->msi, &config_addr); /* Releasing MSIs */ if (!req_num) { @@ -415,7 +415,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr, irq, req_num); /* Add MSI device to cache */ - msi = g_new(spapr_pci_msi, 1); + msi = g_new(SpaprPciMsi, 1); msi->first_irq = irq; msi->num = req_num; config_addr_key = g_new(int, 1); @@ -446,7 +446,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu, unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3); SpaprPhbState *phb = NULL; PCIDevice *pdev = NULL; - spapr_pci_msi *msi; + SpaprPciMsi *msi; /* Find SpaprPhbState */ phb = spapr_pci_find_phb(spapr, buid); @@ -459,7 +459,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu, } /* Find device descriptor and start IRQ */ - msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr); + msi = (SpaprPciMsi *) g_hash_table_lookup(phb->msi, &config_addr); if (!msi || !msi->first_irq || !msi->num || (ioa_intr_num >= msi->num)) { trace_spapr_pci_msi("Failed to return vector", config_addr); rtas_st(rets, 0, RTAS_OUT_HW_ERROR); @@ -1700,11 +1700,13 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, state = func_drck->dr_entity_sense(func_drc); if (state == SPAPR_DR_ENTITY_SENSE_PRESENT && !spapr_drc_unplug_requested(func_drc)) { - error_setg(errp, - "PCI: slot %d, function %d still present. " - "Must unplug all non-0 functions first.", - slotnr, i); - return; + /* + * Attempting to remove function 0 of a multifunction + * device will will cascade into removing all child + * functions, even if their unplug weren't requested + * beforehand. + */ + spapr_drc_detach(func_drc); } } } @@ -1804,7 +1806,7 @@ static void spapr_phb_destroy_msi(gpointer opaque) { SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); - spapr_pci_msi *msi = opaque; + SpaprPciMsi *msi = opaque; if (!smc->legacy_irq_allocation) { spapr_irq_msi_free(spapr, msi->first_irq, msi->num); @@ -1825,6 +1827,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) SysBusDevice *s = SYS_BUS_DEVICE(dev); SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(s); PCIHostState *phb = PCI_HOST_BRIDGE(s); + MachineState *ms = MACHINE(spapr); char *namebuf; int i; PCIBus *bus; @@ -1877,7 +1880,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) } if (sphb->numa_node != -1 && - (sphb->numa_node >= MAX_NODES || !numa_info[sphb->numa_node].present)) { + (sphb->numa_node >= MAX_NODES || + !ms->numa_state->nodes[sphb->numa_node].present)) { error_setg(errp, "Invalid NUMA node ID for PCI host bridge"); return; } @@ -2118,7 +2122,7 @@ static const VMStateDescription vmstate_spapr_pci_lsi = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32_EQUAL(irq, struct spapr_pci_lsi, NULL), + VMSTATE_UINT32_EQUAL(irq, SpaprPciLsi, NULL), VMSTATE_END_OF_LIST() }, @@ -2129,9 +2133,9 @@ static const VMStateDescription vmstate_spapr_pci_msi = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField []) { - VMSTATE_UINT32(key, spapr_pci_msi_mig), - VMSTATE_UINT32(value.first_irq, spapr_pci_msi_mig), - VMSTATE_UINT32(value.num, spapr_pci_msi_mig), + VMSTATE_UINT32(key, SpaprPciMsiMig), + VMSTATE_UINT32(value.first_irq, SpaprPciMsiMig), + VMSTATE_UINT32(value.num, SpaprPciMsiMig), VMSTATE_END_OF_LIST() }, }; @@ -2163,12 +2167,12 @@ static int spapr_pci_pre_save(void *opaque) if (!sphb->msi_devs_num) { return 0; } - sphb->msi_devs = g_new(spapr_pci_msi_mig, sphb->msi_devs_num); + sphb->msi_devs = g_new(SpaprPciMsiMig, sphb->msi_devs_num); g_hash_table_iter_init(&iter, sphb->msi); for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) { sphb->msi_devs[i].key = *(uint32_t *) key; - sphb->msi_devs[i].value = *(spapr_pci_msi *) value; + sphb->msi_devs[i].value = *(SpaprPciMsi *) value; } return 0; @@ -2215,10 +2219,10 @@ static const VMStateDescription vmstate_spapr_pci = { VMSTATE_UINT64_TEST(mig_io_win_addr, SpaprPhbState, pre_2_8_migration), VMSTATE_UINT64_TEST(mig_io_win_size, SpaprPhbState, pre_2_8_migration), VMSTATE_STRUCT_ARRAY(lsi_table, SpaprPhbState, PCI_NUM_PINS, 0, - vmstate_spapr_pci_lsi, struct spapr_pci_lsi), + vmstate_spapr_pci_lsi, SpaprPciLsi), VMSTATE_INT32(msi_devs_num, SpaprPhbState), VMSTATE_STRUCT_VARRAY_ALLOC(msi_devs, SpaprPhbState, msi_devs_num, 0, - vmstate_spapr_pci_msi, spapr_pci_msi_mig), + vmstate_spapr_pci_msi, SpaprPciMsiMig), VMSTATE_END_OF_LIST() }, }; diff --git a/hw/ppc/spapr_pci_nvlink2.c b/hw/ppc/spapr_pci_nvlink2.c index eda8c752aa..4aa89ede23 100644 --- a/hw/ppc/spapr_pci_nvlink2.c +++ b/hw/ppc/spapr_pci_nvlink2.c @@ -39,11 +39,7 @@ #define SPAPR_GPU_NUMA_ID (cpu_to_be32(1)) -struct spapr_phb_pci_nvgpu_config { - uint64_t nv2_ram_current; - uint64_t nv2_atsd_current; - int num; /* number of non empty (i.e. tgt!=0) entries in slots[] */ - struct spapr_phb_pci_nvgpu_slot { +typedef struct SpaprPhbPciNvGpuSlot { uint64_t tgt; uint64_t gpa; unsigned numa_id; @@ -54,12 +50,18 @@ struct spapr_phb_pci_nvgpu_config { PCIDevice *npdev; uint32_t link_speed; } links[NVGPU_MAX_LINKS]; - } slots[NVGPU_MAX_NUM]; +} SpaprPhbPciNvGpuSlot; + +struct SpaprPhbPciNvGpuConfig { + uint64_t nv2_ram_current; + uint64_t nv2_atsd_current; + int num; /* number of non empty (i.e. tgt!=0) entries in slots[] */ + SpaprPhbPciNvGpuSlot slots[NVGPU_MAX_NUM]; Error *errp; }; -static struct spapr_phb_pci_nvgpu_slot * -spapr_nvgpu_get_slot(struct spapr_phb_pci_nvgpu_config *nvgpus, uint64_t tgt) +static SpaprPhbPciNvGpuSlot * +spapr_nvgpu_get_slot(SpaprPhbPciNvGpuConfig *nvgpus, uint64_t tgt) { int i; @@ -81,13 +83,13 @@ spapr_nvgpu_get_slot(struct spapr_phb_pci_nvgpu_config *nvgpus, uint64_t tgt) return &nvgpus->slots[i]; } -static void spapr_pci_collect_nvgpu(struct spapr_phb_pci_nvgpu_config *nvgpus, +static void spapr_pci_collect_nvgpu(SpaprPhbPciNvGpuConfig *nvgpus, PCIDevice *pdev, uint64_t tgt, MemoryRegion *mr, Error **errp) { MachineState *machine = MACHINE(qdev_get_machine()); SpaprMachineState *spapr = SPAPR_MACHINE(machine); - struct spapr_phb_pci_nvgpu_slot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt); + SpaprPhbPciNvGpuSlot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt); if (!nvslot) { error_setg(errp, "Found too many GPUs per vPHB"); @@ -102,11 +104,11 @@ static void spapr_pci_collect_nvgpu(struct spapr_phb_pci_nvgpu_config *nvgpus, ++spapr->gpu_numa_id; } -static void spapr_pci_collect_nvnpu(struct spapr_phb_pci_nvgpu_config *nvgpus, +static void spapr_pci_collect_nvnpu(SpaprPhbPciNvGpuConfig *nvgpus, PCIDevice *pdev, uint64_t tgt, MemoryRegion *mr, Error **errp) { - struct spapr_phb_pci_nvgpu_slot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt); + SpaprPhbPciNvGpuSlot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt); int j; if (!nvslot) { @@ -138,7 +140,7 @@ static void spapr_phb_pci_collect_nvgpu(PCIBus *bus, PCIDevice *pdev, if (tgt) { Error *local_err = NULL; - struct spapr_phb_pci_nvgpu_config *nvgpus = opaque; + SpaprPhbPciNvGpuConfig *nvgpus = opaque; Object *mr_gpu = object_property_get_link(po, "nvlink2-mr[0]", NULL); Object *mr_npu = object_property_get_link(po, "nvlink2-atsd-mr[0]", NULL); @@ -177,7 +179,7 @@ void spapr_phb_nvgpu_setup(SpaprPhbState *sphb, Error **errp) return; } - sphb->nvgpus = g_new0(struct spapr_phb_pci_nvgpu_config, 1); + sphb->nvgpus = g_new0(SpaprPhbPciNvGpuConfig, 1); sphb->nvgpus->nv2_ram_current = sphb->nv2_gpa_win_addr; sphb->nvgpus->nv2_atsd_current = sphb->nv2_atsd_win_addr; @@ -194,7 +196,7 @@ void spapr_phb_nvgpu_setup(SpaprPhbState *sphb, Error **errp) /* Add found GPU RAM and ATSD MRs if found */ for (i = 0, valid_gpu_num = 0; i < sphb->nvgpus->num; ++i) { Object *nvmrobj; - struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; + SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; if (!nvslot->gpdev) { continue; @@ -242,7 +244,7 @@ void spapr_phb_nvgpu_free(SpaprPhbState *sphb) } for (i = 0; i < sphb->nvgpus->num; ++i) { - struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; + SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev), "nvlink2-mr[0]", NULL); @@ -276,7 +278,7 @@ void spapr_phb_nvgpu_populate_dt(SpaprPhbState *sphb, void *fdt, int bus_off, } for (i = 0; (i < sphb->nvgpus->num) && (atsdnum < ARRAY_SIZE(atsd)); ++i) { - struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; + SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; if (!nvslot->gpdev) { continue; @@ -354,7 +356,7 @@ void spapr_phb_nvgpu_ram_populate_dt(SpaprPhbState *sphb, void *fdt) /* Add memory nodes for GPU RAM and mark them unusable */ for (i = 0; i < sphb->nvgpus->num; ++i) { - struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; + SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev), "nvlink2-mr[0]", NULL); uint32_t associativity[] = { @@ -398,7 +400,7 @@ void spapr_phb_nvgpu_populate_pcidev_dt(PCIDevice *dev, void *fdt, int offset, } for (i = 0; i < sphb->nvgpus->num; ++i) { - struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; + SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; /* Skip "slot" without attached GPU */ if (!nvslot->gpdev) { diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 526b489297..bee3835214 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -266,6 +266,7 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, target_ulong args, uint32_t nret, target_ulong rets) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); MachineState *ms = MACHINE(qdev_get_machine()); unsigned int max_cpus = ms->smp.max_cpus; target_ulong parameter = rtas_ld(args, 0); @@ -283,6 +284,20 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, current_machine->ram_size / MiB, ms->smp.cpus, max_cpus); + if (pcc->n_host_threads > 0) { + char *hostthr_val, *old = param_val; + + /* + * Add HostThrs property. This property is not present in PAPR but + * is expected by some guests to communicate the number of physical + * host threads per core on the system so that they can scale + * information which varies based on the thread configuration. + */ + hostthr_val = g_strdup_printf(",HostThrs=%d", pcc->n_host_threads); + param_val = g_strconcat(param_val, hostthr_val, NULL); + g_free(hostthr_val); + g_free(old); + } ret = sysparm_st(buffer, length, param_val, strlen(param_val) + 1); g_free(param_val); break; diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 00235148be..4b3bd4a804 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -15,6 +15,7 @@ #include "cpu.h" #include "s390-pci-inst.h" #include "s390-pci-bus.h" +#include "exec/memop.h" #include "exec/memory-internal.h" #include "qemu/error-report.h" #include "sysemu/hw_accel.h" @@ -372,7 +373,8 @@ static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias, mr = pbdev->pdev->io_regions[pcias].memory; mr = s390_get_subregion(mr, offset, len); offset -= mr->addr; - return memory_region_dispatch_read(mr, offset, data, len, + return memory_region_dispatch_read(mr, offset, data, + size_memop(len) | MO_BE, MEMTXATTRS_UNSPECIFIED); } @@ -471,7 +473,8 @@ static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias, mr = pbdev->pdev->io_regions[pcias].memory; mr = s390_get_subregion(mr, offset, len); offset -= mr->addr; - return memory_region_dispatch_write(mr, offset, data, len, + return memory_region_dispatch_write(mr, offset, data, + size_memop(len) | MO_BE, MEMTXATTRS_UNSPECIFIED); } @@ -780,8 +783,8 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, for (i = 0; i < len / 8; i++) { result = memory_region_dispatch_write(mr, offset + i * 8, - ldq_p(buffer + i * 8), 8, - MEMTXATTRS_UNSPECIFIED); + ldq_p(buffer + i * 8), + MO_64, MEMTXATTRS_UNSPECIFIED); if (result != MEMTX_OK) { s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index ed81d5c44c..59c2bbeee6 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -44,6 +44,13 @@ enum timer_ctrl_op { op_pulse_enable }; +/* + * Minimum value of the reload register to filter out short period + * timers which have a noticeable impact in emulation. 5us should be + * enough, use 20us for "safety". + */ +#define TIMER_MIN_NS (20 * SCALE_US) + /** * Avoid mutual references between AspeedTimerCtrlState and AspeedTimer * structs, as it's a waste of memory. The ptimer BH callback needs to know @@ -98,6 +105,14 @@ static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t now_ns) return t->reload - MIN(t->reload, ticks); } +static uint32_t calculate_min_ticks(AspeedTimer *t, uint32_t value) +{ + uint32_t rate = calculate_rate(t); + uint32_t min_ticks = muldiv64(TIMER_MIN_NS, rate, NANOSECONDS_PER_SECOND); + + return value < min_ticks ? min_ticks : value; +} + static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks) { uint64_t delta_ns; @@ -261,7 +276,7 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg, switch (reg) { case TIMER_REG_RELOAD: old_reload = t->reload; - t->reload = value; + t->reload = calculate_min_ticks(t, value); /* If the reload value was not previously set, or zero, and * the current value is valid, try to start the timer if it is diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 9846e4b513..7c07295519 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -2038,26 +2038,36 @@ static void usb_mtp_realize(USBDevice *dev, Error **errp) { MTPState *s = USB_MTP(dev); - usb_desc_create_serial(dev); - usb_desc_init(dev); - QTAILQ_INIT(&s->objects); - if (s->desc == NULL) { - if (s->root == NULL) { - error_setg(errp, "usb-mtp: rootdir property must be configured"); - return; - } - s->desc = strrchr(s->root, '/'); - if (s->desc && s->desc[0]) { - s->desc = g_strdup(s->desc + 1); - } else { - s->desc = g_strdup("none"); - } + if ((s->root == NULL) || !g_path_is_absolute(s->root)) { + error_setg(errp, "usb-mtp: rootdir must be configured and be an absolute path"); + return; } + + if (access(s->root, R_OK) != 0) { + error_setg(errp, "usb-mtp: rootdir does not exist/not readable"); + return; + } else if (!s->readonly && access(s->root, W_OK) != 0) { + error_setg(errp, "usb-mtp: rootdir does not have write permissions"); + return; + } + /* Mark store as RW */ if (!s->readonly) { s->flags |= (1 << MTP_FLAG_WRITABLE); } + if (s->desc == NULL) { + /* + * This does not check if path exists + * but we have the checks above + */ + s->desc = g_path_get_basename(s->root); + } + + usb_desc_create_serial(dev); + usb_desc_init(dev); + QTAILQ_INIT(&s->objects); + } static const VMStateDescription vmstate_usb_mtp = { diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index f578264948..80988bb305 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1914,6 +1914,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) } usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); if (xfer->packet.status == USB_RET_NAK) { + xhci_xfer_unmap(xfer); return; } xhci_try_complete_packet(xfer); @@ -2161,6 +2162,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, DeviceOutRequest | USB_REQ_SET_ADDRESS, slotid, 0, 0, NULL); assert(p.status != USB_RET_ASYNC); + usb_packet_cleanup(&p); } res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx); diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index f71aace156..136f3a9ad6 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -11,6 +11,7 @@ */ #include "qemu/osdep.h" +#include "exec/memop.h" #include "qemu/units.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" @@ -1073,7 +1074,8 @@ static void vfio_rtl8168_quirk_address_write(void *opaque, hwaddr addr, /* Write to the proper guest MSI-X table instead */ memory_region_dispatch_write(&vdev->pdev.msix_table_mmio, - offset, val, size, + offset, val, + size_memop(size) | MO_LE, MEMTXATTRS_UNSPECIFIED); } return; /* Do not write guest MSI-X data to hardware */ @@ -1104,7 +1106,8 @@ static uint64_t vfio_rtl8168_quirk_data_read(void *opaque, if (rtl->enabled && (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) { hwaddr offset = rtl->addr & 0xfff; memory_region_dispatch_read(&vdev->pdev.msix_table_mmio, offset, - &data, size, MEMTXATTRS_UNSPECIFIED); + &data, size_memop(size) | MO_LE, + MEMTXATTRS_UNSPECIFIED); trace_vfio_quirk_rtl8168_msix_read(vdev->vbasedev.name, offset, data); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 8babd92e59..c6b47a9c73 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -17,6 +17,7 @@ #include "qemu/osdep.h" +#include "exec/memop.h" #include "standard-headers/linux/virtio_pci.h" #include "hw/virtio/virtio.h" #include "migration/qemu-file-types.h" @@ -543,16 +544,17 @@ void virtio_address_space_write(VirtIOPCIProxy *proxy, hwaddr addr, val = pci_get_byte(buf); break; case 2: - val = cpu_to_le16(pci_get_word(buf)); + val = pci_get_word(buf); break; case 4: - val = cpu_to_le32(pci_get_long(buf)); + val = pci_get_long(buf); break; default: /* As length is under guest control, handle illegal values. */ return; } - memory_region_dispatch_write(mr, addr, val, len, MEMTXATTRS_UNSPECIFIED); + memory_region_dispatch_write(mr, addr, val, size_memop(len) | MO_LE, + MEMTXATTRS_UNSPECIFIED); } static void @@ -575,16 +577,17 @@ virtio_address_space_read(VirtIOPCIProxy *proxy, hwaddr addr, /* Make sure caller aligned buf properly */ assert(!(((uintptr_t)buf) & (len - 1))); - memory_region_dispatch_read(mr, addr, &val, len, MEMTXATTRS_UNSPECIFIED); + memory_region_dispatch_read(mr, addr, &val, size_memop(len) | MO_LE, + MEMTXATTRS_UNSPECIFIED); switch (len) { case 1: pci_set_byte(buf, val); break; case 2: - pci_set_word(buf, le16_to_cpu(val)); + pci_set_word(buf, val); break; case 4: - pci_set_long(buf, le32_to_cpu(val)); + pci_set_long(buf, val); break; default: /* As length is under guest control, handle illegal values. */ @@ -601,6 +604,10 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, pci_default_write_config(pci_dev, address, val, len); + if (proxy->flags & VIRTIO_PCI_FLAG_INIT_FLR) { + pcie_cap_flr_write_config(pci_dev, address, val, len); + } + if (range_covers_byte(address, len, PCI_COMMAND) && !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { virtio_pci_stop_ioeventfd(proxy); @@ -1777,6 +1784,10 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) pcie_ats_init(pci_dev, 256); } + if (proxy->flags & VIRTIO_PCI_FLAG_INIT_FLR) { + /* Set Function Level Reset capability bit */ + pcie_cap_flr_init(pci_dev); + } } else { /* * make future invocations of pci_is_express() return false @@ -1844,6 +1855,8 @@ static Property virtio_pci_properties[] = { VIRTIO_PCI_FLAG_INIT_LNKCTL_BIT, true), DEFINE_PROP_BIT("x-pcie-pm-init", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_INIT_PM_BIT, true), + DEFINE_PROP_BIT("x-pcie-flr-init", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_INIT_FLR_BIT, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 292275acb1..e2eaaa9182 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -44,6 +44,7 @@ enum { VIRTIO_PCI_FLAG_INIT_DEVERR_BIT, VIRTIO_PCI_FLAG_INIT_LNKCTL_BIT, VIRTIO_PCI_FLAG_INIT_PM_BIT, + VIRTIO_PCI_FLAG_INIT_FLR_BIT, }; /* Need to activate work-arounds for buggy guests at vmstate load. */ @@ -80,6 +81,9 @@ enum { /* Init Power Management */ #define VIRTIO_PCI_FLAG_INIT_PM (1 << VIRTIO_PCI_FLAG_INIT_PM_BIT) +/* Init Function Level Reset capability */ +#define VIRTIO_PCI_FLAG_INIT_FLR (1 << VIRTIO_PCI_FLAG_INIT_FLR_BIT) + typedef struct { MSIMessage msg; int virq; diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index d1650e1dee..e93bed020f 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -192,27 +192,24 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp) } if (vrng->conf.rng == NULL) { - vrng->conf.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM)); + Object *default_backend = object_new(TYPE_RNG_BUILTIN); - user_creatable_complete(USER_CREATABLE(vrng->conf.default_backend), + user_creatable_complete(USER_CREATABLE(default_backend), &local_err); if (local_err) { error_propagate(errp, local_err); - object_unref(OBJECT(vrng->conf.default_backend)); + object_unref(default_backend); return; } - object_property_add_child(OBJECT(dev), - "default-backend", - OBJECT(vrng->conf.default_backend), - NULL); + object_property_add_child(OBJECT(dev), "default-backend", + default_backend, &error_abort); /* The child property took a reference, we can safely drop ours now */ - object_unref(OBJECT(vrng->conf.default_backend)); + object_unref(default_backend); - object_property_set_link(OBJECT(dev), - OBJECT(vrng->conf.default_backend), - "rng", NULL); + object_property_set_link(OBJECT(dev), default_backend, + "rng", &error_abort); } vrng->rng = vrng->conf.rng; diff --git a/include/block/nbd.h b/include/block/nbd.h index 7b36d672f0..21550747cf 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -140,6 +140,7 @@ enum { NBD_FLAG_CAN_MULTI_CONN_BIT = 8, /* Multi-client cache consistent */ NBD_FLAG_SEND_RESIZE_BIT = 9, /* Send resize */ NBD_FLAG_SEND_CACHE_BIT = 10, /* Send CACHE (prefetch) */ + NBD_FLAG_SEND_FAST_ZERO_BIT = 11, /* FAST_ZERO flag for WRITE_ZEROES */ }; #define NBD_FLAG_HAS_FLAGS (1 << NBD_FLAG_HAS_FLAGS_BIT) @@ -153,6 +154,7 @@ enum { #define NBD_FLAG_CAN_MULTI_CONN (1 << NBD_FLAG_CAN_MULTI_CONN_BIT) #define NBD_FLAG_SEND_RESIZE (1 << NBD_FLAG_SEND_RESIZE_BIT) #define NBD_FLAG_SEND_CACHE (1 << NBD_FLAG_SEND_CACHE_BIT) +#define NBD_FLAG_SEND_FAST_ZERO (1 << NBD_FLAG_SEND_FAST_ZERO_BIT) /* New-style handshake (global) flags, sent from server to client, and control what will happen during handshake phase. */ @@ -205,6 +207,7 @@ enum { #define NBD_CMD_FLAG_DF (1 << 2) /* don't fragment structured read */ #define NBD_CMD_FLAG_REQ_ONE (1 << 3) /* only one extent in BLOCK_STATUS * reply chunk */ +#define NBD_CMD_FLAG_FAST_ZERO (1 << 4) /* fail if WRITE_ZEROES is not fast */ /* Supported request types */ enum { @@ -270,6 +273,7 @@ static inline bool nbd_reply_type_is_error(int type) #define NBD_EINVAL 22 #define NBD_ENOSPC 28 #define NBD_EOVERFLOW 75 +#define NBD_ENOTSUP 95 #define NBD_ESHUTDOWN 108 /* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */ @@ -326,7 +330,7 @@ typedef struct NBDClient NBDClient; NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, uint64_t size, const char *name, const char *desc, - const char *bitmap, uint16_t nbdflags, + const char *bitmap, bool readonly, bool shared, void (*close)(NBDExport *), bool writethrough, BlockBackend *on_eject_blk, Error **errp); void nbd_export_close(NBDExport *exp); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 8323094648..d2d443c4f9 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -329,14 +329,14 @@ CPUArchState *cpu_copy(CPUArchState *env); #define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS - 2)) /* Set if TLB entry is an IO callback. */ #define TLB_MMIO (1 << (TARGET_PAGE_BITS - 3)) -/* Set if TLB entry must have MMU lookup repeated for every access */ -#define TLB_RECHECK (1 << (TARGET_PAGE_BITS - 4)) +/* Set if TLB entry contains a watchpoint. */ +#define TLB_WATCHPOINT (1 << (TARGET_PAGE_BITS - 4)) /* Use this mask to check interception with an alignment mask * in a TCG backend. */ -#define TLB_FLAGS_MASK (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \ - | TLB_RECHECK) +#define TLB_FLAGS_MASK \ + (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO | TLB_WATCHPOINT) /** * tlb_hit_page: return true if page aligned @addr is a hit against the diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 189709b6de..be946ba1ce 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -231,7 +231,7 @@ typedef struct CPUTLB { } CPUTLB; #endif /* !CONFIG_USER_ONLY && CONFIG_TCG */ /* - * This structure must be placed in ArchCPU immedately + * This structure must be placed in ArchCPU immediately * before CPUArchState, as a field named "neg". */ typedef struct CPUNegativeOffsetState { diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 135aeaab0d..81b02eb2fe 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -260,8 +260,6 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, void tlb_set_page(CPUState *cpu, target_ulong vaddr, hwaddr paddr, int prot, int mmu_idx, target_ulong size); -void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx, - uintptr_t retaddr); #else static inline void tlb_init(CPUState *cpu) { @@ -312,6 +310,14 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu, { } #endif +void *probe_access(CPUArchState *env, target_ulong addr, int size, + MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); + +static inline void *probe_write(CPUArchState *env, target_ulong addr, int size, + int mmu_idx, uintptr_t retaddr) +{ + return probe_access(env, addr, size, MMU_DATA_STORE, mmu_idx, retaddr); +} #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h index d4a3477d71..95f2d20d55 100644 --- a/include/exec/memattrs.h +++ b/include/exec/memattrs.h @@ -37,6 +37,8 @@ typedef struct MemTxAttrs { unsigned int user:1; /* Requester ID (for MSI for example) */ unsigned int requester_id:16; + /* Invert endianness for this page */ + unsigned int byte_swap:1; /* * The following are target-specific page-table bits. These are not * related to actual memory transactions at all. However, this structure diff --git a/include/exec/memop.h b/include/exec/memop.h new file mode 100644 index 0000000000..529d07b02d --- /dev/null +++ b/include/exec/memop.h @@ -0,0 +1,134 @@ +/* + * Constants for memory operations + * + * Authors: + * Richard Henderson <rth@twiddle.net> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef MEMOP_H +#define MEMOP_H + +#include "qemu/host-utils.h" + +typedef enum MemOp { + MO_8 = 0, + MO_16 = 1, + MO_32 = 2, + MO_64 = 3, + MO_SIZE = 3, /* Mask for the above. */ + + MO_SIGN = 4, /* Sign-extended, otherwise zero-extended. */ + + MO_BSWAP = 8, /* Host reverse endian. */ +#ifdef HOST_WORDS_BIGENDIAN + MO_LE = MO_BSWAP, + MO_BE = 0, +#else + MO_LE = 0, + MO_BE = MO_BSWAP, +#endif +#ifdef NEED_CPU_H +#ifdef TARGET_WORDS_BIGENDIAN + MO_TE = MO_BE, +#else + MO_TE = MO_LE, +#endif +#endif + + /* + * MO_UNALN accesses are never checked for alignment. + * MO_ALIGN accesses will result in a call to the CPU's + * do_unaligned_access hook if the guest address is not aligned. + * The default depends on whether the target CPU defines + * TARGET_ALIGNED_ONLY. + * + * Some architectures (e.g. ARMv8) need the address which is aligned + * to a size more than the size of the memory access. + * Some architectures (e.g. SPARCv9) need an address which is aligned, + * but less strictly than the natural alignment. + * + * MO_ALIGN supposes the alignment size is the size of a memory access. + * + * There are three options: + * - unaligned access permitted (MO_UNALN). + * - an alignment to the size of an access (MO_ALIGN); + * - an alignment to a specified size, which may be more or less than + * the access size (MO_ALIGN_x where 'x' is a size in bytes); + */ + MO_ASHIFT = 4, + MO_AMASK = 7 << MO_ASHIFT, +#ifdef NEED_CPU_H +#ifdef TARGET_ALIGNED_ONLY + MO_ALIGN = 0, + MO_UNALN = MO_AMASK, +#else + MO_ALIGN = MO_AMASK, + MO_UNALN = 0, +#endif +#endif + MO_ALIGN_2 = 1 << MO_ASHIFT, + MO_ALIGN_4 = 2 << MO_ASHIFT, + MO_ALIGN_8 = 3 << MO_ASHIFT, + MO_ALIGN_16 = 4 << MO_ASHIFT, + MO_ALIGN_32 = 5 << MO_ASHIFT, + MO_ALIGN_64 = 6 << MO_ASHIFT, + + /* Combinations of the above, for ease of use. */ + MO_UB = MO_8, + MO_UW = MO_16, + MO_UL = MO_32, + MO_SB = MO_SIGN | MO_8, + MO_SW = MO_SIGN | MO_16, + MO_SL = MO_SIGN | MO_32, + MO_Q = MO_64, + + MO_LEUW = MO_LE | MO_UW, + MO_LEUL = MO_LE | MO_UL, + MO_LESW = MO_LE | MO_SW, + MO_LESL = MO_LE | MO_SL, + MO_LEQ = MO_LE | MO_Q, + + MO_BEUW = MO_BE | MO_UW, + MO_BEUL = MO_BE | MO_UL, + MO_BESW = MO_BE | MO_SW, + MO_BESL = MO_BE | MO_SL, + MO_BEQ = MO_BE | MO_Q, + +#ifdef NEED_CPU_H + MO_TEUW = MO_TE | MO_UW, + MO_TEUL = MO_TE | MO_UL, + MO_TESW = MO_TE | MO_SW, + MO_TESL = MO_TE | MO_SL, + MO_TEQ = MO_TE | MO_Q, +#endif + + MO_SSIZE = MO_SIZE | MO_SIGN, +} MemOp; + +/* MemOp to size in bytes. */ +static inline unsigned memop_size(MemOp op) +{ + return 1 << (op & MO_SIZE); +} + +/* Size in bytes to MemOp. */ +static inline MemOp size_memop(unsigned size) +{ +#ifdef CONFIG_DEBUG_TCG + /* Power of 2 up to 8. */ + assert((size & (size - 1)) == 0 && size >= 1 && size <= 8); +#endif + return ctz32(size); +} + +/* Big endianness from MemOp. */ +static inline bool memop_big_endian(MemOp op) +{ + return (op & MO_BSWAP) == MO_BE; +} + +#endif diff --git a/include/exec/memory.h b/include/exec/memory.h index fddc2ff48a..2dd810259d 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -19,6 +19,7 @@ #include "exec/cpu-common.h" #include "exec/hwaddr.h" #include "exec/memattrs.h" +#include "exec/memop.h" #include "exec/ramlist.h" #include "qemu/bswap.h" #include "qemu/queue.h" @@ -1087,16 +1088,6 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr, void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n); /** - * memory_region_iommu_replay_all: replay existing IOMMU translations - * to all the notifiers registered. - * - * Note: this is not related to record-and-replay functionality. - * - * @iommu_mr: the memory region to observe - */ -void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr); - -/** * memory_region_unregister_iommu_notifier: unregister a notifier for * changes to IOMMU translation entries. * @@ -1749,13 +1740,13 @@ void mtree_info(bool flatview, bool dispatch_tree, bool owner); * @mr: #MemoryRegion to access * @addr: address within that region * @pval: pointer to uint64_t which the data is written to - * @size: size of the access in bytes + * @op: size, sign, and endianness of the memory operation * @attrs: memory transaction attributes to use for the access */ MemTxResult memory_region_dispatch_read(MemoryRegion *mr, hwaddr addr, uint64_t *pval, - unsigned size, + MemOp op, MemTxAttrs attrs); /** * memory_region_dispatch_write: perform a write directly to the specified @@ -1764,13 +1755,13 @@ MemTxResult memory_region_dispatch_read(MemoryRegion *mr, * @mr: #MemoryRegion to access * @addr: address within that region * @data: data to write - * @size: size of the access in bytes + * @op: size, sign, and endianness of the memory operation * @attrs: memory transaction attributes to use for the access */ MemTxResult memory_region_dispatch_write(MemoryRegion *mr, hwaddr addr, uint64_t data, - unsigned size, + MemOp op, MemTxAttrs attrs); /** @@ -2210,6 +2201,9 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr, } } +/* enum device_endian to MemOp. */ +MemOp devend_memop(enum device_endian end); + #endif #endif diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 1a563ad756..991cf05134 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -414,7 +414,7 @@ build_append_gas_from_struct(GArray *table, const struct AcpiGenericAddress *s) void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base, uint64_t len, int node, MemoryAffinityFlags flags); -void build_slit(GArray *table_data, BIOSLinker *linker); +void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms); void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, const char *oem_id, const char *oem_table_id); diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h index 5714dea1a2..7f4d0ca7cd 100644 --- a/include/hw/arm/boot.h +++ b/include/hw/arm/boot.h @@ -131,7 +131,7 @@ struct arm_boot_info { * before sysbus-fdt arm_register_platform_bus_fdt_creator. Indeed the * machine init done notifiers are called in registration reverse order. */ -void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info); +void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info); AddressSpace *arm_boot_address_space(ARMCPU *cpu, const struct arm_boot_info *info); @@ -158,7 +158,7 @@ AddressSpace *arm_boot_address_space(ARMCPU *cpu, * Note: Must not be called unless have_dtb(binfo) is true. */ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, - hwaddr addr_limit, AddressSpace *as); + hwaddr addr_limit, AddressSpace *as, MachineState *ms); /* Write a secure board setup routine with a dummy handler for SMCs */ void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu, diff --git a/include/hw/boards.h b/include/hw/boards.h index ced86109ec..2289536e48 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -299,6 +299,7 @@ struct MachineState { CPUArchIdList *possible_cpus; CpuTopology smp; struct NVDIMMState *nvdimms_state; + struct NumaState *numa_state; }; #define DEFINE_MACHINE(namestr, machine_initfn) \ diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h index d5196c53e6..794b653484 100644 --- a/include/hw/char/escc.h +++ b/include/hw/char/escc.h @@ -51,6 +51,7 @@ typedef struct ESCCState { struct ESCCChannelState chn[2]; uint32_t it_shift; + bool bit_swap; MemoryRegion mmio; uint32_t disabled; uint32_t frequency; diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 77fca95a40..c7cda65c66 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -1070,12 +1070,49 @@ static inline bool cpu_breakpoint_test(CPUState *cpu, vaddr pc, int mask) return false; } +#ifdef CONFIG_USER_ONLY +static inline int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len, + int flags, CPUWatchpoint **watchpoint) +{ + return -ENOSYS; +} + +static inline int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, + vaddr len, int flags) +{ + return -ENOSYS; +} + +static inline void cpu_watchpoint_remove_by_ref(CPUState *cpu, + CPUWatchpoint *wp) +{ +} + +static inline void cpu_watchpoint_remove_all(CPUState *cpu, int mask) +{ +} + +static inline void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, + MemTxAttrs atr, int fl, uintptr_t ra) +{ +} + +static inline int cpu_watchpoint_address_matches(CPUState *cpu, + vaddr addr, vaddr len) +{ + return 0; +} +#else int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len, int flags, CPUWatchpoint **watchpoint); int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len, int flags); void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint); void cpu_watchpoint_remove_all(CPUState *cpu, int mask); +void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, + MemTxAttrs attrs, int flags, uintptr_t ra); +int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len); +#endif /** * cpu_get_address_space: diff --git a/include/hw/m68k/next-cube.h b/include/hw/m68k/next-cube.h new file mode 100644 index 0000000000..a3be2b32ab --- /dev/null +++ b/include/hw/m68k/next-cube.h @@ -0,0 +1,47 @@ + +#ifndef NEXT_CUBE_H +#define NEXT_CUBE_H + +#define TYPE_NEXTFB "next-fb" + +#define TYPE_NEXTKBD "next-kbd" + +enum next_dma_chan { + NEXTDMA_FD, + NEXTDMA_ENRX, + NEXTDMA_ENTX, + NEXTDMA_SCSI, + NEXTDMA_SCC, + NEXTDMA_SND +}; + +#define DMA_ENABLE 0x01000000 +#define DMA_SUPDATE 0x02000000 +#define DMA_COMPLETE 0x08000000 + +#define DMA_M2DEV 0x0 +#define DMA_SETENABLE 0x00010000 +#define DMA_SETSUPDATE 0x00020000 +#define DMA_DEV2M 0x00040000 +#define DMA_CLRCOMPLETE 0x00080000 +#define DMA_RESET 0x00100000 + +enum next_irqs { + NEXT_FD_I, + NEXT_KBD_I, + NEXT_PWR_I, + NEXT_ENRX_I, + NEXT_ENTX_I, + NEXT_SCSI_I, + NEXT_CLK_I, + NEXT_SCC_I, + NEXT_ENTX_DMA_I, + NEXT_ENRX_DMA_I, + NEXT_SCSI_DMA_I, + NEXT_SCC_DMA_I, + NEXT_SND_I +}; + +void next_irq(void *opaque, int number, int level); + +#endif /* NEXT_CUBE_H */ diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 1b61162f91..abd87605b2 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -34,15 +34,21 @@ typedef struct SpaprPhbState SpaprPhbState; -typedef struct spapr_pci_msi { +typedef struct SpaprPciMsi { uint32_t first_irq; uint32_t num; -} spapr_pci_msi; +} SpaprPciMsi; -typedef struct spapr_pci_msi_mig { +typedef struct SpaprPciMsiMig { uint32_t key; - spapr_pci_msi value; -} spapr_pci_msi_mig; + SpaprPciMsi value; +} SpaprPciMsiMig; + +typedef struct SpaprPciLsi { + uint32_t irq; +} SpaprPciLsi; + +typedef struct SpaprPhbPciNvGpuConfig SpaprPhbPciNvGpuConfig; struct SpaprPhbState { PCIHostState parent_obj; @@ -63,14 +69,12 @@ struct SpaprPhbState { AddressSpace iommu_as; MemoryRegion iommu_root; - struct spapr_pci_lsi { - uint32_t irq; - } lsi_table[PCI_NUM_PINS]; + SpaprPciLsi lsi_table[PCI_NUM_PINS]; GHashTable *msi; /* Temporary cache for migration purposes */ int32_t msi_devs_num; - spapr_pci_msi_mig *msi_devs; + SpaprPciMsiMig *msi_devs; QLIST_ENTRY(SpaprPhbState) list; @@ -89,7 +93,7 @@ struct SpaprPhbState { hwaddr mig_io_win_addr, mig_io_win_size; hwaddr nv2_gpa_win_addr; hwaddr nv2_atsd_win_addr; - struct spapr_phb_pci_nvgpu_config *nvgpus; + SpaprPhbPciNvGpuConfig *nvgpus; }; #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index fa7c380edb..03111fd55b 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -121,6 +121,7 @@ struct SpaprMachineClass { bool legacy_irq_allocation; bool broken_host_serial_model; /* present real host info to the guest */ bool pre_4_1_migration; /* don't migrate hpt-max-page-size */ + bool linux_pci_probe; void (*phb_placement)(SpaprMachineState *spapr, uint32_t index, uint64_t *buid, hwaddr *pio, diff --git a/include/hw/virtio/virtio-rng.h b/include/hw/virtio/virtio-rng.h index ff699335e3..bd05d734b8 100644 --- a/include/hw/virtio/virtio-rng.h +++ b/include/hw/virtio/virtio-rng.h @@ -14,7 +14,6 @@ #include "hw/virtio/virtio.h" #include "sysemu/rng.h" -#include "sysemu/rng-random.h" #include "standard-headers/linux/virtio_rng.h" #define TYPE_VIRTIO_RNG "virtio-rng-device" @@ -27,7 +26,6 @@ struct VirtIORNGConf { RngBackend *rng; uint64_t max_bytes; uint32_t period_ms; - RngRandom *default_backend; }; typedef struct VirtIORNG { diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h index d7134d2cd6..777ff5954e 100644 --- a/include/io/channel-socket.h +++ b/include/io/channel-socket.h @@ -123,6 +123,7 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc, * qio_channel_socket_listen_sync: * @ioc: the socket channel object * @addr: the address to listen to + * @num: the expected ammount of connections * @errp: pointer to a NULL-initialized error object * * Attempt to listen to the address @addr. This method @@ -132,12 +133,14 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc, */ int qio_channel_socket_listen_sync(QIOChannelSocket *ioc, SocketAddress *addr, + int num, Error **errp); /** * qio_channel_socket_listen_async: * @ioc: the socket channel object * @addr: the address to listen to + * @num: the expected ammount of connections * @callback: the function to invoke on completion * @opaque: user data to pass to @callback * @destroy: the function to free @opaque @@ -153,6 +156,7 @@ int qio_channel_socket_listen_sync(QIOChannelSocket *ioc, */ void qio_channel_socket_listen_async(QIOChannelSocket *ioc, SocketAddress *addr, + int num, QIOTaskFunc callback, gpointer opaque, GDestroyNotify destroy, diff --git a/include/io/net-listener.h b/include/io/net-listener.h index 8081ac58a2..fb101703e3 100644 --- a/include/io/net-listener.h +++ b/include/io/net-listener.h @@ -95,6 +95,7 @@ void qio_net_listener_set_name(QIONetListener *listener, * qio_net_listener_open_sync: * @listener: the network listener object * @addr: the address to listen on + * @num: the amount of expected connections * @errp: pointer to a NULL initialized error object * * Synchronously open a listening connection on all @@ -104,6 +105,7 @@ void qio_net_listener_set_name(QIONetListener *listener, */ int qio_net_listener_open_sync(QIONetListener *listener, SocketAddress *addr, + int num, Error **errp); /** diff --git a/include/qemu/memfd.h b/include/qemu/memfd.h index d551c28b68..975b6bdb77 100644 --- a/include/qemu/memfd.h +++ b/include/qemu/memfd.h @@ -32,6 +32,10 @@ #define MFD_HUGE_SHIFT 26 #endif +#if defined CONFIG_LINUX && !defined CONFIG_MEMFD +int memfd_create(const char *name, unsigned int flags); +#endif + int qemu_memfd_create(const char *name, size_t size, bool hugetlb, uint64_t hugetlbsize, unsigned int seals, Error **errp); bool qemu_memfd_alloc_check(void); diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 8140fea685..57cd049d6e 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -41,7 +41,7 @@ int unix_connect(const char *path, Error **errp); SocketAddress *socket_parse(const char *str, Error **errp); int socket_connect(SocketAddress *addr, Error **errp); -int socket_listen(SocketAddress *addr, Error **errp); +int socket_listen(SocketAddress *addr, int num, Error **errp); void socket_listen_cleanup(int fd, Error **errp); int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp); diff --git a/include/sysemu/numa.h b/include/sysemu/numa.h index 7a4ce89765..ae9c41d02b 100644 --- a/include/sysemu/numa.h +++ b/include/sysemu/numa.h @@ -14,9 +14,6 @@ struct CPUArchId; #define NUMA_DISTANCE_MAX 254 #define NUMA_DISTANCE_UNREACHABLE 255 -extern int nb_numa_nodes; /* Number of NUMA nodes */ -extern bool have_numa_distance; - struct NodeInfo { uint64_t node_mem; struct HostMemoryBackend *node_memdev; @@ -29,12 +26,22 @@ struct NumaNodeMem { uint64_t node_plugged_mem; }; -extern NodeInfo numa_info[MAX_NODES]; +struct NumaState { + /* Number of NUMA nodes */ + int num_nodes; + + /* Allow setting NUMA distance for different NUMA nodes */ + bool have_numa_distance; + + /* NUMA nodes information */ + NodeInfo nodes[MAX_NODES]; +}; +typedef struct NumaState NumaState; void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp); void parse_numa_opts(MachineState *ms); void numa_complete_configuration(MachineState *ms); -void query_numa_node_mem(NumaNodeMem node_mem[]); +void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms); extern QemuOptsList qemu_numa_opts; void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes, int nb_nodes, ram_addr_t size); diff --git a/include/sysemu/rng.h b/include/sysemu/rng.h index 9b22c156f8..fa6eada78c 100644 --- a/include/sysemu/rng.h +++ b/include/sysemu/rng.h @@ -24,6 +24,8 @@ #define RNG_BACKEND_CLASS(klass) \ OBJECT_CLASS_CHECK(RngBackendClass, (klass), TYPE_RNG_BACKEND) +#define TYPE_RNG_BUILTIN "rng-builtin" + typedef struct RngRequest RngRequest; typedef struct RngBackendClass RngBackendClass; typedef struct RngBackend RngBackend; diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index d2c38f611a..44f18eb739 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -42,8 +42,6 @@ extern const char *keyboard_layout; extern int win2k_install_hack; extern int alt_grab; extern int ctrl_grab; -extern int smp_cpus; -extern unsigned int max_cpus; extern int cursor_hide; extern int graphic_rotate; extern int no_quit; diff --git a/io/channel-socket.c b/io/channel-socket.c index bec3d931d1..b74f5b92a0 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -197,12 +197,13 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc, int qio_channel_socket_listen_sync(QIOChannelSocket *ioc, SocketAddress *addr, + int num, Error **errp) { int fd; - trace_qio_channel_socket_listen_sync(ioc, addr); - fd = socket_listen(addr, errp); + trace_qio_channel_socket_listen_sync(ioc, addr, num); + fd = socket_listen(addr, num, errp); if (fd < 0) { trace_qio_channel_socket_listen_fail(ioc); return -1; @@ -219,14 +220,27 @@ int qio_channel_socket_listen_sync(QIOChannelSocket *ioc, } +struct QIOChannelListenWorkerData { + SocketAddress *addr; + int num; /* amount of expected connections */ +}; + +static void qio_channel_listen_worker_free(gpointer opaque) +{ + struct QIOChannelListenWorkerData *data = opaque; + + qapi_free_SocketAddress(data->addr); + g_free(data); +} + static void qio_channel_socket_listen_worker(QIOTask *task, gpointer opaque) { QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); - SocketAddress *addr = opaque; + struct QIOChannelListenWorkerData *data = opaque; Error *err = NULL; - qio_channel_socket_listen_sync(ioc, addr, &err); + qio_channel_socket_listen_sync(ioc, data->addr, data->num, &err); qio_task_set_error(task, err); } @@ -234,6 +248,7 @@ static void qio_channel_socket_listen_worker(QIOTask *task, void qio_channel_socket_listen_async(QIOChannelSocket *ioc, SocketAddress *addr, + int num, QIOTaskFunc callback, gpointer opaque, GDestroyNotify destroy, @@ -241,16 +256,18 @@ void qio_channel_socket_listen_async(QIOChannelSocket *ioc, { QIOTask *task = qio_task_new( OBJECT(ioc), callback, opaque, destroy); - SocketAddress *addrCopy; + struct QIOChannelListenWorkerData *data; - addrCopy = QAPI_CLONE(SocketAddress, addr); + data = g_new0(struct QIOChannelListenWorkerData, 1); + data->addr = QAPI_CLONE(SocketAddress, addr); + data->num = num; /* socket_listen() blocks in DNS lookups, so we must use a thread */ - trace_qio_channel_socket_listen_async(ioc, addr); + trace_qio_channel_socket_listen_async(ioc, addr, num); qio_task_run_in_thread(task, qio_channel_socket_listen_worker, - addrCopy, - (GDestroyNotify)qapi_free_SocketAddress, + data, + qio_channel_listen_worker_free, context); } diff --git a/io/net-listener.c b/io/net-listener.c index d8cfe52673..5d8a226872 100644 --- a/io/net-listener.c +++ b/io/net-listener.c @@ -62,6 +62,7 @@ static gboolean qio_net_listener_channel_func(QIOChannel *ioc, int qio_net_listener_open_sync(QIONetListener *listener, SocketAddress *addr, + int num, Error **errp) { QIODNSResolver *resolver = qio_dns_resolver_get_instance(); @@ -82,7 +83,7 @@ int qio_net_listener_open_sync(QIONetListener *listener, for (i = 0; i < nresaddrs; i++) { QIOChannelSocket *sioc = qio_channel_socket_new(); - if (qio_channel_socket_listen_sync(sioc, resaddrs[i], + if (qio_channel_socket_listen_sync(sioc, resaddrs[i], num, err ? NULL : &err) == 0) { success = true; diff --git a/io/trace-events b/io/trace-events index 378390521e..d7bc70b966 100644 --- a/io/trace-events +++ b/io/trace-events @@ -17,8 +17,8 @@ qio_channel_socket_connect_sync(void *ioc, void *addr) "Socket connect sync ioc= qio_channel_socket_connect_async(void *ioc, void *addr) "Socket connect async ioc=%p addr=%p" qio_channel_socket_connect_fail(void *ioc) "Socket connect fail ioc=%p" qio_channel_socket_connect_complete(void *ioc, int fd) "Socket connect complete ioc=%p fd=%d" -qio_channel_socket_listen_sync(void *ioc, void *addr) "Socket listen sync ioc=%p addr=%p" -qio_channel_socket_listen_async(void *ioc, void *addr) "Socket listen async ioc=%p addr=%p" +qio_channel_socket_listen_sync(void *ioc, void *addr, int num) "Socket listen sync ioc=%p addr=%p num=%d" +qio_channel_socket_listen_async(void *ioc, void *addr, int num) "Socket listen async ioc=%p addr=%p num=%d" qio_channel_socket_listen_fail(void *ioc) "Socket listen fail ioc=%p" qio_channel_socket_listen_complete(void *ioc, int fd) "Socket listen complete ioc=%p fd=%d" qio_channel_socket_dgram_sync(void *ioc, void *localAddr, void *remoteAddr) "Socket dgram sync ioc=%p localAddr=%p remoteAddr=%p" diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h index 8a3764919a..3f79356a07 100644 --- a/linux-user/arm/target_cpu.h +++ b/linux-user/arm/target_cpu.h @@ -19,9 +19,27 @@ #ifndef ARM_TARGET_CPU_H #define ARM_TARGET_CPU_H -/* We need to be able to map the commpage. - See validate_guest_space in linux-user/elfload.c. */ -#define MAX_RESERVED_VA 0xffff0000ul +static inline unsigned long arm_max_reserved_va(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + + if (arm_feature(&cpu->env, ARM_FEATURE_M)) { + /* + * There are magic return addresses above 0xfe000000, + * and in general a lot of M-profile system stuff in + * the high addresses. Restrict linux-user to the + * cached write-back RAM in the system map. + */ + return 0x80000000ul; + } else { + /* + * We need to be able to map the commpage. + * See validate_guest_space in linux-user/elfload.c. + */ + return 0xffff0000ul; + } +} +#define MAX_RESERVED_VA arm_max_reserved_va static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp) { diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 3365e192eb..f6693e5760 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -607,9 +607,23 @@ enum { ARM_HWCAP_A64_SB = 1 << 29, ARM_HWCAP_A64_PACA = 1 << 30, ARM_HWCAP_A64_PACG = 1UL << 31, + + ARM_HWCAP2_A64_DCPODP = 1 << 0, + ARM_HWCAP2_A64_SVE2 = 1 << 1, + ARM_HWCAP2_A64_SVEAES = 1 << 2, + ARM_HWCAP2_A64_SVEPMULL = 1 << 3, + ARM_HWCAP2_A64_SVEBITPERM = 1 << 4, + ARM_HWCAP2_A64_SVESHA3 = 1 << 5, + ARM_HWCAP2_A64_SVESM4 = 1 << 6, + ARM_HWCAP2_A64_FLAGM2 = 1 << 7, + ARM_HWCAP2_A64_FRINT = 1 << 8, }; -#define ELF_HWCAP get_elf_hwcap() +#define ELF_HWCAP get_elf_hwcap() +#define ELF_HWCAP2 get_elf_hwcap2() + +#define GET_FEATURE_ID(feat, hwcap) \ + do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0) static uint32_t get_elf_hwcap(void) { @@ -621,8 +635,6 @@ static uint32_t get_elf_hwcap(void) hwcaps |= ARM_HWCAP_A64_CPUID; /* probe for the extra features */ -#define GET_FEATURE_ID(feat, hwcap) \ - do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0) GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES); GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL); @@ -645,11 +657,22 @@ static uint32_t get_elf_hwcap(void) GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB); GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM); -#undef GET_FEATURE_ID + return hwcaps; +} + +static uint32_t get_elf_hwcap2(void) +{ + ARMCPU *cpu = ARM_CPU(thread_cpu); + uint32_t hwcaps = 0; + + GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2); + GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT); return hwcaps; } +#undef GET_FEATURE_ID + #endif /* not TARGET_AARCH64 */ #endif /* TARGET_ARM */ @@ -2380,6 +2403,8 @@ static void load_elf_image(const char *image_name, int image_fd, } info->load_bias = load_bias; + info->code_offset = load_bias; + info->data_offset = load_bias; info->load_addr = load_addr; info->entry = ehdr->e_entry + load_bias; info->start_code = -1; diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 3281c97ca2..c6b9d6ad66 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -112,6 +112,14 @@ IOCTL(BLKZEROOUT, IOC_W, MK_PTR(MK_ARRAY(TYPE_ULONGLONG, 2))) #endif + IOCTL(FDMSGON, 0, TYPE_NULL) + IOCTL(FDMSGOFF, 0, TYPE_NULL) + IOCTL(FDFLUSH, 0, TYPE_NULL) + IOCTL(FDRESET, 0, TYPE_NULL) + IOCTL(FDRAWCMD, 0, TYPE_NULL) + IOCTL(FDTWADDLE, 0, TYPE_NULL) + IOCTL(FDEJECT, 0, TYPE_NULL) + #ifdef FIBMAP IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG)) #endif @@ -177,6 +185,8 @@ #endif #endif /* CONFIG_USBFS */ + IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT)) IOCTL(SIOCATMARK, IOC_R, MK_PTR(TYPE_INT)) IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_int_ifreq))) IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) @@ -246,6 +256,9 @@ IOCTL(RNDADDTOENTCNT, IOC_W, MK_PTR(TYPE_INT)) IOCTL(RNDZAPENTCNT, 0, TYPE_NULL) IOCTL(RNDCLEARPOOL, 0, TYPE_NULL) +#ifdef RNDRESEEDCRNG + IOCTL(RNDRESEEDCRNG, 0, TYPE_NULL) +#endif IOCTL(CDROMPAUSE, 0, TYPE_NULL) IOCTL(CDROMSTART, 0, TYPE_NULL) diff --git a/linux-user/main.c b/linux-user/main.c index 47917bbb20..560d053f72 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -49,7 +49,6 @@ char *exec_path; int singlestep; -static const char *filename; static const char *argv0; static int gdbstub_port; static envlist_t *envlist; @@ -78,12 +77,12 @@ int have_guest_base; (TARGET_LONG_BITS == 32 || defined(TARGET_ABI32)) /* There are a number of places where we assign reserved_va to a variable of type abi_ulong and expect it to fit. Avoid the last page. */ -# define MAX_RESERVED_VA (0xfffffffful & TARGET_PAGE_MASK) +# define MAX_RESERVED_VA(CPU) (0xfffffffful & TARGET_PAGE_MASK) # else -# define MAX_RESERVED_VA (1ul << TARGET_VIRT_ADDR_SPACE_BITS) +# define MAX_RESERVED_VA(CPU) (1ul << TARGET_VIRT_ADDR_SPACE_BITS) # endif # else -# define MAX_RESERVED_VA 0 +# define MAX_RESERVED_VA(CPU) 0 # endif #endif @@ -236,7 +235,7 @@ static void handle_arg_log(const char *arg) static void handle_arg_dfilter(const char *arg) { - qemu_set_dfilter_ranges(arg, NULL); + qemu_set_dfilter_ranges(arg, &error_fatal); } static void handle_arg_log_filename(const char *arg) @@ -357,8 +356,7 @@ static void handle_arg_reserved_va(const char *arg) unsigned long unshifted = reserved_va; p++; reserved_va <<= shift; - if (reserved_va >> shift != unshifted - || (MAX_RESERVED_VA && reserved_va > MAX_RESERVED_VA)) { + if (reserved_va >> shift != unshifted) { fprintf(stderr, "Reserved virtual address too big\n"); exit(EXIT_FAILURE); } @@ -393,6 +391,13 @@ static void handle_arg_trace(const char *arg) trace_file = trace_opt_parse(arg); } +#if defined(TARGET_XTENSA) +static void handle_arg_abi_call0(const char *arg) +{ + xtensa_set_abi_call0(); +} +#endif + struct qemu_argument { const char *argv; const char *env; @@ -446,6 +451,10 @@ static const struct qemu_argument arg_table[] = { "", "[[enable=]<pattern>][,events=<file>][,file=<file>]"}, {"version", "QEMU_VERSION", false, handle_arg_version, "", "display version information and exit"}, +#if defined(TARGET_XTENSA) + {"xtensa-abi-call0", "QEMU_XTENSA_ABI_CALL0", false, handle_arg_abi_call0, + "", "assume CALL0 Xtensa ABI"}, +#endif {NULL, NULL, false, NULL, NULL, NULL} }; @@ -586,7 +595,6 @@ static int parse_args(int argc, char **argv) exit(EXIT_FAILURE); } - filename = argv[optind]; exec_path = argv[optind]; return optind; @@ -607,6 +615,7 @@ int main(int argc, char **argv, char **envp) int i; int ret; int execfd; + unsigned long max_reserved_va; error_init(argv[0]); module_call_init(MODULE_INIT_TRACE); @@ -657,9 +666,9 @@ int main(int argc, char **argv, char **envp) execfd = qemu_getauxval(AT_EXECFD); if (execfd == 0) { - execfd = open(filename, O_RDONLY); + execfd = open(exec_path, O_RDONLY); if (execfd < 0) { - printf("Error while loading %s: %s\n", filename, strerror(errno)); + printf("Error while loading %s: %s\n", exec_path, strerror(errno)); _exit(EXIT_FAILURE); } } @@ -672,31 +681,31 @@ int main(int argc, char **argv, char **envp) /* init tcg before creating CPUs and to get qemu_host_page_size */ tcg_exec_init(0); - /* Reserving *too* much vm space via mmap can run into problems - with rlimits, oom due to page table creation, etc. We will still try it, - if directed by the command-line option, but not by default. */ - if (HOST_LONG_BITS == 64 && - TARGET_VIRT_ADDR_SPACE_BITS <= 32 && - reserved_va == 0) { - /* reserved_va must be aligned with the host page size - * as it is used with mmap() - */ - reserved_va = MAX_RESERVED_VA & qemu_host_page_mask; - } - cpu = cpu_create(cpu_type); env = cpu->env_ptr; cpu_reset(cpu); - thread_cpu = cpu; - if (getenv("QEMU_STRACE")) { - do_strace = 1; + /* + * Reserving too much vm space via mmap can run into problems + * with rlimits, oom due to page table creation, etc. We will + * still try it, if directed by the command-line option, but + * not by default. + */ + max_reserved_va = MAX_RESERVED_VA(cpu); + if (reserved_va != 0) { + if (max_reserved_va && reserved_va > max_reserved_va) { + fprintf(stderr, "Reserved virtual address too big\n"); + exit(EXIT_FAILURE); + } + } else if (HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32) { + /* + * reserved_va must be aligned with the host page size + * as it is used with mmap() + */ + reserved_va = max_reserved_va & qemu_host_page_mask; } - if (seed_optarg == NULL) { - seed_optarg = getenv("QEMU_RAND_SEED"); - } { Error *err = NULL; if (seed_optarg != NULL) { @@ -784,10 +793,10 @@ int main(int argc, char **argv, char **envp) cpu->opaque = ts; task_settid(ts); - ret = loader_exec(execfd, filename, target_argv, target_environ, regs, + ret = loader_exec(execfd, exec_path, target_argv, target_environ, regs, info, &bprm); if (ret != 0) { - printf("Error while loading %s: %s\n", filename, strerror(-ret)); + printf("Error while loading %s: %s\n", exec_path, strerror(-ret)); _exit(EXIT_FAILURE); } diff --git a/linux-user/openrisc/target_elf.h b/linux-user/openrisc/target_elf.h index 40ceb025c9..265ecd3079 100644 --- a/linux-user/openrisc/target_elf.h +++ b/linux-user/openrisc/target_elf.h @@ -9,6 +9,6 @@ #define OPENRISC_TARGET_ELF_H static inline const char *cpu_get_model(uint32_t eflags) { - return "or1200"; + return "any"; } #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8b41a03901..e2af3c1494 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" #include "qemu/path.h" +#include "qemu/memfd.h" #include "qemu/queue.h" #include <elf.h> #include <endian.h> @@ -88,6 +89,7 @@ #include <linux/kd.h> #include <linux/mtio.h> #include <linux/fs.h> +#include <linux/fd.h> #if defined(CONFIG_FIEMAP) #include <linux/fiemap.h> #endif @@ -11847,7 +11849,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, timer_t htimer = g_posix_timers[timerid]; ret = get_errno(timer_getoverrun(htimer)); } - fd_trans_unregister(ret); return ret; } #endif @@ -11939,6 +11940,17 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, /* PowerPC specific. */ return do_swapcontext(cpu_env, arg1, arg2, arg3); #endif +#ifdef TARGET_NR_memfd_create + case TARGET_NR_memfd_create: + p = lock_user_string(arg1); + if (!p) { + return -TARGET_EFAULT; + } + ret = get_errno(memfd_create(p, arg2)); + fd_trans_unregister(ret); + unlock_user(p, arg1, 0); + return ret; +#endif default: qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 0662270300..fa69c6ab8d 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -758,10 +758,14 @@ struct target_pollfd { #if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SH4) || \ defined(TARGET_XTENSA) +#define TARGET_FIOGETOWN TARGET_IOR('f', 123, int) +#define TARGET_FIOSETOWN TARGET_IOW('f', 124, int) #define TARGET_SIOCATMARK TARGET_IOR('s', 7, int) #define TARGET_SIOCSPGRP TARGET_IOW('s', 8, pid_t) #define TARGET_SIOCGPGRP TARGET_IOR('s', 9, pid_t) #else +#define TARGET_FIOGETOWN 0x8903 +#define TARGET_FIOSETOWN 0x8901 #define TARGET_SIOCATMARK 0x8905 #define TARGET_SIOCSPGRP 0x8902 #define TARGET_SIOCGPGRP 0x8904 @@ -850,6 +854,7 @@ struct target_pollfd { #define TARGET_RNDADDTOENTCNT TARGET_IOW('R', 0x01, int) #define TARGET_RNDZAPENTCNT TARGET_IO('R', 0x04) #define TARGET_RNDCLEARPOOL TARGET_IO('R', 0x06) +#define TARGET_RNDRESEEDCRNG TARGET_IO('R', 0x07) /* From <linux/fs.h> */ @@ -883,6 +888,16 @@ struct target_pollfd { #define TARGET_BLKROTATIONAL TARGET_IO(0x12, 126) #define TARGET_BLKZEROOUT TARGET_IO(0x12, 127) +/* From <linux/fd.h> */ + +#define TARGET_FDMSGON TARGET_IO(2, 0x45) +#define TARGET_FDMSGOFF TARGET_IO(2, 0x46) +#define TARGET_FDFLUSH TARGET_IO(2, 0x4b) +#define TARGET_FDRESET TARGET_IO(2, 0x54) +#define TARGET_FDRAWCMD TARGET_IO(2, 0x58) +#define TARGET_FDTWADDLE TARGET_IO(2, 0x59) +#define TARGET_FDEJECT TARGET_IO(2, 0x5a) + #define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */ #define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */ diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c index 8d54ef3ae3..590f0313ff 100644 --- a/linux-user/xtensa/signal.c +++ b/linux-user/xtensa/signal.c @@ -134,6 +134,8 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, abi_ulong frame_addr; struct target_rt_sigframe *frame; uint32_t ra; + bool abi_call0; + unsigned base; int i; frame_addr = get_sigframe(ka, env, sizeof(*frame)); @@ -182,20 +184,27 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(0x00, &frame->retcode[5]); #endif } - env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); - if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER)) { - env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT); - } memset(env->regs, 0, sizeof(env->regs)); env->pc = ka->_sa_handler; env->regs[1] = frame_addr; env->sregs[WINDOW_BASE] = 0; env->sregs[WINDOW_START] = 1; - env->regs[4] = (ra & 0x3fffffff) | 0x40000000; - env->regs[6] = sig; - env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, info); - env->regs[8] = frame_addr + offsetof(struct target_rt_sigframe, uc); + abi_call0 = (env->sregs[PS] & PS_WOE) == 0; + env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); + + if (abi_call0) { + base = 0; + env->regs[base] = ra; + } else { + env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT); + base = 4; + env->regs[base] = (ra & 0x3fffffff) | 0x40000000; + } + env->regs[base + 2] = sig; + env->regs[base + 3] = frame_addr + offsetof(struct target_rt_sigframe, + info); + env->regs[base + 4] = frame_addr + offsetof(struct target_rt_sigframe, uc); unlock_user_struct(frame, frame_addr, 1); return; @@ -351,32 +351,23 @@ static bool memory_region_big_endian(MemoryRegion *mr) #endif } -static bool memory_region_wrong_endianness(MemoryRegion *mr) +static void adjust_endianness(MemoryRegion *mr, uint64_t *data, MemOp op) { -#ifdef TARGET_WORDS_BIGENDIAN - return mr->ops->endianness == DEVICE_LITTLE_ENDIAN; -#else - return mr->ops->endianness == DEVICE_BIG_ENDIAN; -#endif -} - -static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size) -{ - if (memory_region_wrong_endianness(mr)) { - switch (size) { - case 1: + if ((op & MO_BSWAP) != devend_memop(mr->ops->endianness)) { + switch (op & MO_SIZE) { + case MO_8: break; - case 2: + case MO_16: *data = bswap16(*data); break; - case 4: + case MO_32: *data = bswap32(*data); break; - case 8: + case MO_64: *data = bswap64(*data); break; default: - abort(); + g_assert_not_reached(); } } } @@ -1446,9 +1437,10 @@ static MemTxResult memory_region_dispatch_read1(MemoryRegion *mr, MemTxResult memory_region_dispatch_read(MemoryRegion *mr, hwaddr addr, uint64_t *pval, - unsigned size, + MemOp op, MemTxAttrs attrs) { + unsigned size = memop_size(op); MemTxResult r; if (!memory_region_access_valid(mr, addr, size, false, attrs)) { @@ -1457,7 +1449,7 @@ MemTxResult memory_region_dispatch_read(MemoryRegion *mr, } r = memory_region_dispatch_read1(mr, addr, pval, size, attrs); - adjust_endianness(mr, pval, size); + adjust_endianness(mr, pval, op); return r; } @@ -1490,15 +1482,17 @@ static bool memory_region_dispatch_write_eventfds(MemoryRegion *mr, MemTxResult memory_region_dispatch_write(MemoryRegion *mr, hwaddr addr, uint64_t data, - unsigned size, + MemOp op, MemTxAttrs attrs) { + unsigned size = memop_size(op); + if (!memory_region_access_valid(mr, addr, size, true, attrs)) { unassigned_mem_write(mr, addr, data, size); return MEMTX_DECODE_ERROR; } - adjust_endianness(mr, &data, size); + adjust_endianness(mr, &data, op); if ((!kvm_eventfds_enabled()) && memory_region_dispatch_write_eventfds(mr, addr, data, size, attrs)) { @@ -1922,15 +1916,6 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) } } -void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr) -{ - IOMMUNotifier *notifier; - - IOMMU_NOTIFIER_FOREACH(notifier, iommu_mr) { - memory_region_iommu_replay(iommu_mr, notifier); - } -} - void memory_region_unregister_iommu_notifier(MemoryRegion *mr, IOMMUNotifier *n) { @@ -2347,7 +2332,7 @@ void memory_region_add_eventfd(MemoryRegion *mr, } if (size) { - adjust_endianness(mr, &mrfd.data, size); + adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE); } memory_region_transaction_begin(); for (i = 0; i < mr->ioeventfd_nb; ++i) { @@ -2382,7 +2367,7 @@ void memory_region_del_eventfd(MemoryRegion *mr, unsigned i; if (size) { - adjust_endianness(mr, &mrfd.data, size); + adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE); } memory_region_transaction_begin(); for (i = 0; i < mr->ioeventfd_nb; ++i) { @@ -3282,3 +3267,21 @@ static void memory_register_types(void) } type_init(memory_register_types) + +MemOp devend_memop(enum device_endian end) +{ + static MemOp conv[] = { + [DEVICE_LITTLE_ENDIAN] = MO_LE, + [DEVICE_BIG_ENDIAN] = MO_BE, + [DEVICE_NATIVE_ENDIAN] = MO_TE, + [DEVICE_HOST_ENDIAN] = 0, + }; + switch (end) { + case DEVICE_LITTLE_ENDIAN: + case DEVICE_BIG_ENDIAN: + case DEVICE_NATIVE_ENDIAN: + return conv[end]; + default: + g_assert_not_reached(); + } +} diff --git a/memory_ldst.inc.c b/memory_ldst.inc.c index acf865b900..c54aee4a95 100644 --- a/memory_ldst.inc.c +++ b/memory_ldst.inc.c @@ -38,16 +38,8 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL, release_lock |= prepare_mmio_access(mr); /* I/O case */ - r = memory_region_dispatch_read(mr, addr1, &val, 4, attrs); -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap32(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap32(val); - } -#endif + r = memory_region_dispatch_read(mr, addr1, &val, + MO_32 | devend_memop(endian), attrs); } else { /* RAM case */ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); @@ -114,16 +106,8 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL, release_lock |= prepare_mmio_access(mr); /* I/O case */ - r = memory_region_dispatch_read(mr, addr1, &val, 8, attrs); -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap64(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap64(val); - } -#endif + r = memory_region_dispatch_read(mr, addr1, &val, + MO_64 | devend_memop(endian), attrs); } else { /* RAM case */ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); @@ -188,7 +172,7 @@ uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, release_lock |= prepare_mmio_access(mr); /* I/O case */ - r = memory_region_dispatch_read(mr, addr1, &val, 1, attrs); + r = memory_region_dispatch_read(mr, addr1, &val, MO_8, attrs); } else { /* RAM case */ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); @@ -224,16 +208,8 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL, release_lock |= prepare_mmio_access(mr); /* I/O case */ - r = memory_region_dispatch_read(mr, addr1, &val, 2, attrs); -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap16(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap16(val); - } -#endif + r = memory_region_dispatch_read(mr, addr1, &val, + MO_16 | devend_memop(endian), attrs); } else { /* RAM case */ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); @@ -300,7 +276,7 @@ void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL, if (l < 4 || !memory_access_is_direct(mr, true)) { release_lock |= prepare_mmio_access(mr); - r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); + r = memory_region_dispatch_write(mr, addr1, val, MO_32, attrs); } else { ptr = qemu_map_ram_ptr(mr->ram_block, addr1); stl_p(ptr, val); @@ -336,17 +312,8 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL, mr = TRANSLATE(addr, &addr1, &l, true, attrs); if (l < 4 || !memory_access_is_direct(mr, true)) { release_lock |= prepare_mmio_access(mr); - -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap32(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap32(val); - } -#endif - r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); + r = memory_region_dispatch_write(mr, addr1, val, + MO_32 | devend_memop(endian), attrs); } else { /* RAM case */ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); @@ -408,7 +375,7 @@ void glue(address_space_stb, SUFFIX)(ARG1_DECL, mr = TRANSLATE(addr, &addr1, &l, true, attrs); if (!memory_access_is_direct(mr, true)) { release_lock |= prepare_mmio_access(mr); - r = memory_region_dispatch_write(mr, addr1, val, 1, attrs); + r = memory_region_dispatch_write(mr, addr1, val, MO_8, attrs); } else { /* RAM case */ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); @@ -441,17 +408,8 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL, mr = TRANSLATE(addr, &addr1, &l, true, attrs); if (l < 2 || !memory_access_is_direct(mr, true)) { release_lock |= prepare_mmio_access(mr); - -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap16(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap16(val); - } -#endif - r = memory_region_dispatch_write(mr, addr1, val, 2, attrs); + r = memory_region_dispatch_write(mr, addr1, val, + MO_16 | devend_memop(endian), attrs); } else { /* RAM case */ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); @@ -514,17 +472,8 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL, mr = TRANSLATE(addr, &addr1, &l, true, attrs); if (l < 8 || !memory_access_is_direct(mr, true)) { release_lock |= prepare_mmio_access(mr); - -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap64(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap64(val); - } -#endif - r = memory_region_dispatch_write(mr, addr1, val, 8, attrs); + r = memory_region_dispatch_write(mr, addr1, val, + MO_64 | devend_memop(endian), attrs); } else { /* RAM case */ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); diff --git a/migration/socket.c b/migration/socket.c index 98efdc0286..97c9efde59 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -178,10 +178,15 @@ static void socket_start_incoming_migration(SocketAddress *saddr, { QIONetListener *listener = qio_net_listener_new(); size_t i; + int num = 1; qio_net_listener_set_name(listener, "migration-socket-listener"); - if (qio_net_listener_open_sync(listener, saddr, errp) < 0) { + if (migrate_use_multifd()) { + num = migrate_multifd_channels(); + } + + if (qio_net_listener_open_sync(listener, saddr, num, errp) < 0) { object_unref(OBJECT(listener)); return; } diff --git a/nbd/client.c b/nbd/client.c index 49bf9906f9..b9dc829175 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Red Hat, Inc. + * Copyright (C) 2016-2019 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws> * * Network Block Device Client Side @@ -142,17 +142,18 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, return 0; } -/* If reply represents success, return 1 without further action. - * If reply represents an error, consume the optional payload of - * the packet on ioc. Then return 0 for unsupported (so the client - * can fall back to other approaches), or -1 with errp set for other - * errors. +/* + * If reply represents success, return 1 without further action. If + * reply represents an error, consume the optional payload of the + * packet on ioc. Then return 0 for unsupported (so the client can + * fall back to other approaches), where @strict determines if only + * ERR_UNSUP or all errors fit that category, or -1 with errp set for + * other errors. */ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, - Error **errp) + bool strict, Error **errp) { - char *msg = NULL; - int result = -1; + g_autofree char *msg = NULL; if (!(reply->type & (1 << 31))) { return 1; @@ -163,26 +164,28 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, error_setg(errp, "server error %" PRIu32 " (%s) message is too long", reply->type, nbd_rep_lookup(reply->type)); - goto cleanup; + goto err; } msg = g_malloc(reply->length + 1); if (nbd_read(ioc, msg, reply->length, NULL, errp) < 0) { error_prepend(errp, "Failed to read option error %" PRIu32 " (%s) message: ", reply->type, nbd_rep_lookup(reply->type)); - goto cleanup; + goto err; } msg[reply->length] = '\0'; trace_nbd_server_error_msg(reply->type, nbd_reply_type_lookup(reply->type), msg); } - switch (reply->type) { - case NBD_REP_ERR_UNSUP: - trace_nbd_reply_err_unsup(reply->option, nbd_opt_lookup(reply->option)); - result = 0; - goto cleanup; + if (reply->type == NBD_REP_ERR_UNSUP || !strict) { + trace_nbd_reply_err_ignored(reply->option, + nbd_opt_lookup(reply->option), + reply->type, nbd_rep_lookup(reply->type)); + return 0; + } + switch (reply->type) { case NBD_REP_ERR_POLICY: error_setg(errp, "Denied by server for option %" PRIu32 " (%s)", reply->option, nbd_opt_lookup(reply->option)); @@ -227,12 +230,9 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, error_append_hint(errp, "server reported: %s\n", msg); } - cleanup: - g_free(msg); - if (result < 0) { - nbd_send_opt_abort(ioc); - } - return result; + err: + nbd_send_opt_abort(ioc); + return -1; } /* nbd_receive_list: @@ -247,18 +247,17 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, Error **errp) { - int ret = -1; NBDOptionReply reply; uint32_t len; uint32_t namelen; - char *local_name = NULL; - char *local_desc = NULL; + g_autofree char *local_name = NULL; + g_autofree char *local_desc = NULL; int error; if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) { return -1; } - error = nbd_handle_reply_err(ioc, &reply, errp); + error = nbd_handle_reply_err(ioc, &reply, true, errp); if (error <= 0) { return error; } @@ -298,7 +297,7 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, local_name = g_malloc(namelen + 1); if (nbd_read(ioc, local_name, namelen, "export name", errp) < 0) { nbd_send_opt_abort(ioc); - goto out; + return -1; } local_name[namelen] = '\0'; len -= namelen; @@ -306,24 +305,17 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, local_desc = g_malloc(len + 1); if (nbd_read(ioc, local_desc, len, "export description", errp) < 0) { nbd_send_opt_abort(ioc); - goto out; + return -1; } local_desc[len] = '\0'; } trace_nbd_receive_list(local_name, local_desc ?: ""); - *name = local_name; - local_name = NULL; + *name = g_steal_pointer(&local_name); if (description) { - *description = local_desc; - local_desc = NULL; + *description = g_steal_pointer(&local_desc); } - ret = 1; - - out: - g_free(local_name); - g_free(local_desc); - return ret; + return 1; } @@ -371,7 +363,7 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) { return -1; } - error = nbd_handle_reply_err(ioc, &reply, errp); + error = nbd_handle_reply_err(ioc, &reply, true, errp); if (error <= 0) { return error; } @@ -546,12 +538,15 @@ static int nbd_receive_query_exports(QIOChannel *ioc, } } -/* nbd_request_simple_option: Send an option request, and parse the reply +/* + * nbd_request_simple_option: Send an option request, and parse the reply. + * @strict controls whether ERR_UNSUP or all errors produce 0 status. * return 1 for successful negotiation, * 0 if operation is unsupported, * -1 with errp set for any other error */ -static int nbd_request_simple_option(QIOChannel *ioc, int opt, Error **errp) +static int nbd_request_simple_option(QIOChannel *ioc, int opt, bool strict, + Error **errp) { NBDOptionReply reply; int error; @@ -563,7 +558,7 @@ static int nbd_request_simple_option(QIOChannel *ioc, int opt, Error **errp) if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) { return -1; } - error = nbd_handle_reply_err(ioc, &reply, errp); + error = nbd_handle_reply_err(ioc, &reply, strict, errp); if (error <= 0) { return error; } @@ -595,7 +590,7 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc, QIOChannelTLS *tioc; struct NBDTLSHandshakeData data = { 0 }; - ret = nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, errp); + ret = nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, true, errp); if (ret <= 0) { if (ret == 0) { error_setg(errp, "Server don't support STARTTLS option"); @@ -695,7 +690,7 @@ static int nbd_receive_one_meta_context(QIOChannel *ioc, return -1; } - ret = nbd_handle_reply_err(ioc, &reply, errp); + ret = nbd_handle_reply_err(ioc, &reply, false, errp); if (ret <= 0) { return ret; } @@ -951,7 +946,7 @@ static int nbd_start_negotiate(AioContext *aio_context, QIOChannel *ioc, if (structured_reply) { result = nbd_request_simple_option(ioc, NBD_OPT_STRUCTURED_REPLY, - errp); + false, errp); if (result < 0) { return -EINVAL; } diff --git a/nbd/common.c b/nbd/common.c index cc8b278e54..ddfe7d1183 100644 --- a/nbd/common.c +++ b/nbd/common.c @@ -201,6 +201,8 @@ const char *nbd_err_lookup(int err) return "ENOSPC"; case NBD_EOVERFLOW: return "EOVERFLOW"; + case NBD_ENOTSUP: + return "ENOTSUP"; case NBD_ESHUTDOWN: return "ESHUTDOWN"; default: @@ -231,6 +233,9 @@ int nbd_errno_to_system_errno(int err) case NBD_EOVERFLOW: ret = EOVERFLOW; break; + case NBD_ENOTSUP: + ret = ENOTSUP; + break; case NBD_ESHUTDOWN: ret = ESHUTDOWN; break; diff --git a/nbd/server.c b/nbd/server.c index f55ccf8edf..28c3c8be85 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -55,6 +55,11 @@ static int system_errno_to_nbd_errno(int err) return NBD_ENOSPC; case EOVERFLOW: return NBD_EOVERFLOW; + case ENOTSUP: +#if ENOTSUP != EOPNOTSUPP + case EOPNOTSUPP: +#endif + return NBD_ENOTSUP; case ESHUTDOWN: return NBD_ESHUTDOWN; case EINVAL: @@ -206,7 +211,7 @@ static int GCC_FMT_ATTR(4, 0) nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type, Error **errp, const char *fmt, va_list va) { - char *msg; + g_autofree char *msg = NULL; int ret; size_t len; @@ -216,18 +221,14 @@ nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type, trace_nbd_negotiate_send_rep_err(msg); ret = nbd_negotiate_send_rep_len(client, type, len, errp); if (ret < 0) { - goto out; + return ret; } if (nbd_write(client->ioc, msg, len, errp) < 0) { error_prepend(errp, "write failed (error message): "); - ret = -EIO; - } else { - ret = 0; + return -EIO; } -out: - g_free(msg); - return ret; + return 0; } /* Send an error reply. @@ -423,14 +424,14 @@ static void nbd_check_meta_export(NBDClient *client) /* Send a reply to NBD_OPT_EXPORT_NAME. * Return -errno on error, 0 on success. */ -static int nbd_negotiate_handle_export_name(NBDClient *client, - uint16_t myflags, bool no_zeroes, +static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes, Error **errp) { char name[NBD_MAX_NAME_SIZE + 1]; char buf[NBD_REPLY_EXPORT_NAME_SIZE] = ""; size_t len; int ret; + uint16_t myflags; /* Client sends: [20 .. xx] export name (length bytes) @@ -458,10 +459,13 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, return -EINVAL; } - trace_nbd_negotiate_new_style_size_flags(client->exp->size, - client->exp->nbdflags | myflags); + myflags = client->exp->nbdflags; + if (client->structured_reply) { + myflags |= NBD_FLAG_SEND_DF; + } + trace_nbd_negotiate_new_style_size_flags(client->exp->size, myflags); stq_be_p(buf, client->exp->size); - stw_be_p(buf + 8, client->exp->nbdflags | myflags); + stw_be_p(buf + 8, myflags); len = no_zeroes ? 10 : sizeof(buf); ret = nbd_write(client->ioc, buf, len, errp); if (ret < 0) { @@ -526,8 +530,7 @@ static int nbd_reject_length(NBDClient *client, bool fatal, Error **errp) /* Handle NBD_OPT_INFO and NBD_OPT_GO. * Return -errno on error, 0 if ready for next option, and 1 to move * into transmission phase. */ -static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, - Error **errp) +static int nbd_negotiate_handle_info(NBDClient *client, Error **errp) { int rc; char name[NBD_MAX_NAME_SIZE + 1]; @@ -540,6 +543,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, uint32_t sizes[3]; char buf[sizeof(uint64_t) + sizeof(uint16_t)]; uint32_t check_align = 0; + uint16_t myflags; /* Client sends: 4 bytes: L, name length (can be 0) @@ -637,10 +641,13 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, } /* Send NBD_INFO_EXPORT always */ - trace_nbd_negotiate_new_style_size_flags(exp->size, - exp->nbdflags | myflags); + myflags = exp->nbdflags; + if (client->structured_reply) { + myflags |= NBD_FLAG_SEND_DF; + } + trace_nbd_negotiate_new_style_size_flags(exp->size, myflags); stq_be_p(buf, exp->size); - stw_be_p(buf + 8, exp->nbdflags | myflags); + stw_be_p(buf + 8, myflags); rc = nbd_negotiate_send_info(client, NBD_INFO_EXPORT, sizeof(buf), buf, errp); if (rc < 0) { @@ -1037,8 +1044,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client, * 1 if client sent NBD_OPT_ABORT, i.e. on valid disconnect, * errp is not set */ -static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, - Error **errp) +static int nbd_negotiate_options(NBDClient *client, Error **errp) { uint32_t flags; bool fixedNewstyle = false; @@ -1172,13 +1178,12 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, return 1; case NBD_OPT_EXPORT_NAME: - return nbd_negotiate_handle_export_name(client, - myflags, no_zeroes, + return nbd_negotiate_handle_export_name(client, no_zeroes, errp); case NBD_OPT_INFO: case NBD_OPT_GO: - ret = nbd_negotiate_handle_info(client, myflags, errp); + ret = nbd_negotiate_handle_info(client, errp); if (ret == 1) { assert(option == NBD_OPT_GO); return 0; @@ -1209,7 +1214,6 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, } else { ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); client->structured_reply = true; - myflags |= NBD_FLAG_SEND_DF; } break; @@ -1232,8 +1236,7 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, */ switch (option) { case NBD_OPT_EXPORT_NAME: - return nbd_negotiate_handle_export_name(client, - myflags, no_zeroes, + return nbd_negotiate_handle_export_name(client, no_zeroes, errp); default: @@ -1259,9 +1262,6 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) { char buf[NBD_OLDSTYLE_NEGOTIATE_SIZE] = ""; int ret; - const uint16_t myflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_TRIM | - NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA | - NBD_FLAG_SEND_WRITE_ZEROES | NBD_FLAG_SEND_CACHE); /* Old style negotiation header, no room for options [ 0 .. 7] passwd ("NBDMAGIC") @@ -1289,7 +1289,7 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) error_prepend(errp, "write failed: "); return -EINVAL; } - ret = nbd_negotiate_options(client, myflags, errp); + ret = nbd_negotiate_options(client, errp); if (ret != 0) { if (ret < 0) { error_prepend(errp, "option negotiation failed: "); @@ -1461,7 +1461,7 @@ static void nbd_eject_notifier(Notifier *n, void *data) NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, uint64_t size, const char *name, const char *desc, - const char *bitmap, uint16_t nbdflags, + const char *bitmap, bool readonly, bool shared, void (*close)(NBDExport *), bool writethrough, BlockBackend *on_eject_blk, Error **errp) { @@ -1485,7 +1485,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, /* Don't allow resize while the NBD server is running, otherwise we don't * care what happens with the node. */ perm = BLK_PERM_CONSISTENT_READ; - if ((nbdflags & NBD_FLAG_READ_ONLY) == 0) { + if (!readonly) { perm |= BLK_PERM_WRITE; } blk = blk_new(bdrv_get_aio_context(bs), perm, @@ -1505,7 +1505,17 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, exp->dev_offset = dev_offset; exp->name = g_strdup(name); exp->description = g_strdup(desc); - exp->nbdflags = nbdflags; + exp->nbdflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_FLUSH | + NBD_FLAG_SEND_FUA | NBD_FLAG_SEND_CACHE); + if (readonly) { + exp->nbdflags |= NBD_FLAG_READ_ONLY; + if (shared) { + exp->nbdflags |= NBD_FLAG_CAN_MULTI_CONN; + } + } else { + exp->nbdflags |= (NBD_FLAG_SEND_TRIM | NBD_FLAG_SEND_WRITE_ZEROES | + NBD_FLAG_SEND_FAST_ZERO); + } assert(size <= INT64_MAX - dev_offset); exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE); @@ -1530,7 +1540,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, goto fail; } - if ((nbdflags & NBD_FLAG_READ_ONLY) && bdrv_is_writable(bs) && + if (readonly && bdrv_is_writable(bs) && bdrv_dirty_bitmap_enabled(bm)) { error_setg(errp, "Enabled bitmap '%s' incompatible with readonly export", @@ -2157,7 +2167,7 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request, if (request->type == NBD_CMD_READ && client->structured_reply) { valid_flags |= NBD_CMD_FLAG_DF; } else if (request->type == NBD_CMD_WRITE_ZEROES) { - valid_flags |= NBD_CMD_FLAG_NO_HOLE; + valid_flags |= NBD_CMD_FLAG_NO_HOLE | NBD_CMD_FLAG_FAST_ZERO; } else if (request->type == NBD_CMD_BLOCK_STATUS) { valid_flags |= NBD_CMD_FLAG_REQ_ONE; } @@ -2296,6 +2306,9 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, if (!(request->flags & NBD_CMD_FLAG_NO_HOLE)) { flags |= BDRV_REQ_MAY_UNMAP; } + if (request->flags & NBD_CMD_FLAG_FAST_ZERO) { + flags |= BDRV_REQ_NO_FALLBACK; + } ret = blk_pwrite_zeroes(exp->blk, request->from + exp->dev_offset, request->len, flags); return nbd_send_generic_reply(client, request->handle, ret, diff --git a/nbd/trace-events b/nbd/trace-events index 7ab6b3788c..f6cde96790 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -4,7 +4,7 @@ nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending option request %" PRIu32" (%s), len %" PRIu32 nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, const char *typename, uint32_t length) "Received option reply %" PRIu32" (%s), type %" PRIu32" (%s), len %" PRIu32 nbd_server_error_msg(uint32_t err, const char *type, const char *msg) "server reported error 0x%" PRIx32 " (%s) with additional message: %s" -nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback" +nbd_reply_err_ignored(uint32_t option, const char *name, uint32_t reply, const char *reply_name) "server failed request %" PRIu32 " (%s) with error 0x%" PRIx32 " (%s), attempting fallback" nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'" nbd_opt_info_go_start(const char *opt, const char *name) "Attempting %s for export '%s'" nbd_opt_info_go_success(const char *opt) "Export is ready after %s request" diff --git a/pc-bios/README b/pc-bios/README index d59cd25461..ad78f6dc49 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20190719. + built from git tag qemu-slof-20190827. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/skiboot.lid b/pc-bios/skiboot.lid Binary files differindex 6d5966c3ae..504b95e8b6 100644 --- a/pc-bios/skiboot.lid +++ b/pc-bios/skiboot.lid diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin Binary files differindex fb0837508b..a3a3e49332 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin diff --git a/qapi/machine.json b/qapi/machine.json index de5c742d72..ca26779f1a 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -348,13 +348,16 @@ # in future versions of QEMU according to the QEMU deprecation # policy (since 4.1.0) # +# @default-cpu-type: default CPU model typename if none is requested via +# the -cpu argument. (since 4.2) +# # Since: 1.2.0 ## { 'struct': 'MachineInfo', 'data': { 'name': 'str', '*alias': 'str', '*is-default': 'bool', 'cpu-max': 'int', 'hotpluggable-cpus': 'bool', 'numa-mem-supported': 'bool', - 'deprecated': 'bool' } } + 'deprecated': 'bool', '*default-cpu-type': 'str' } } ## # @query-machines: diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi index 00a4b6f350..9d74a1cfc0 100644 --- a/qemu-deprecated.texi +++ b/qemu-deprecated.texi @@ -72,6 +72,13 @@ backend settings instead of environment variables. To ease migration to the new format, the ``-audiodev-help'' option can be used to convert the current values of the environment variables to ``-audiodev'' options. +@subsection Creating sound card devices and vnc without audiodev= property (since 4.2) + +When not using the deprecated legacy audio config, each sound card +should specify an @code{audiodev=} property. Additionally, when using +vnc, you should specify an @code{audiodev=} propery if you plan to +transmit audio through the VNC protocol. + @subsection -mon ...,control=readline,pretty=on|off (since 4.1) The @code{pretty=on|off} switch has no effect for HMP monitors, but is diff --git a/qemu-doc.texi b/qemu-doc.texi index 577d1e8376..b47e89cfca 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -11,6 +11,9 @@ @paragraphindent 0 @c %**end of header +@set qemu_system qemu-system-x86_64 +@set qemu_system_x86 qemu-system-x86_64 + @ifinfo @direntry * QEMU: (qemu-doc). The QEMU Emulator User Documentation. @@ -207,12 +210,12 @@ Note that, by default, GUS shares IRQ(7) with parallel ports and so QEMU must be told to not have parallel ports to have working GUS. @example -qemu-system-i386 dos.img -soundhw gus -parallel none +@value{qemu_system_x86} dos.img -soundhw gus -parallel none @end example Alternatively: @example -qemu-system-i386 dos.img -device gus,irq=5 +@value{qemu_system_x86} dos.img -device gus,irq=5 @end example Or some other unclaimed IRQ. @@ -225,10 +228,11 @@ CS4231A is the chip used in Windows Sound System and GUSMAX products @section Quick Start @cindex quick start -Download and uncompress the linux image (@file{linux.img}) and type: +Download and uncompress a hard disk image with Linux installed (e.g. +@file{linux.img}) and type: @example -qemu-system-i386 linux.img +@value{qemu_system} linux.img @end example Linux should boot and give you a prompt. @@ -238,7 +242,7 @@ Linux should boot and give you a prompt. @example @c man begin SYNOPSIS -@command{qemu-system-i386} [@var{options}] [@var{disk_image}] +@command{@value{qemu_system}} [@var{options}] [@var{disk_image}] @c man end @end example @@ -278,28 +282,35 @@ is specified in seconds. The default is 0 which means no timeout. Libiscsi Example (without authentication): @example -qemu-system-i386 -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \ +@value{qemu_system} -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \ -cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \ -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 @end example Example (CHAP username/password via URL): @example -qemu-system-i386 -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1 +@value{qemu_system} -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1 @end example Example (CHAP username/password via environment variables): @example LIBISCSI_CHAP_USERNAME="user" \ LIBISCSI_CHAP_PASSWORD="password" \ -qemu-system-i386 -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 +@value{qemu_system} -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 @end example @item NBD QEMU supports NBD (Network Block Devices) both using TCP protocol as well -as Unix Domain Sockets. +as Unix Domain Sockets. With TCP, the default port is 10809. + +Syntax for specifying a NBD device using TCP, in preferred URI form: +``nbd://<server-ip>[:<port>]/[<export>]'' + +Syntax for specifying a NBD device using Unix Domain Sockets; remember +that '?' is a shell glob character and may need quoting: +``nbd+unix:///[<export>]?socket=<domain-socket>'' -Syntax for specifying a NBD device using TCP +Older syntax that is also recognized: ``nbd:<server-ip>:<port>[:exportname=<export>]'' Syntax for specifying a NBD device using Unix Domain Sockets @@ -307,12 +318,12 @@ Syntax for specifying a NBD device using Unix Domain Sockets Example for TCP @example -qemu-system-i386 --drive file=nbd:192.0.2.1:30000 +@value{qemu_system} --drive file=nbd:192.0.2.1:30000 @end example Example for Unix Domain Sockets @example -qemu-system-i386 --drive file=nbd:unix:/tmp/nbd-socket +@value{qemu_system} --drive file=nbd:unix:/tmp/nbd-socket @end example @item SSH @@ -320,8 +331,8 @@ QEMU supports SSH (Secure Shell) access to remote disks. Examples: @example -qemu-system-i386 -drive file=ssh://user@@host/path/to/disk.img -qemu-system-i386 -drive file.driver=ssh,file.user=user,file.host=host,file.port=22,file.path=/path/to/disk.img +@value{qemu_system} -drive file=ssh://user@@host/path/to/disk.img +@value{qemu_system} -drive file.driver=ssh,file.user=user,file.host=host,file.port=22,file.path=/path/to/disk.img @end example Currently authentication must be done using ssh-agent. Other @@ -339,7 +350,7 @@ sheepdog[+tcp|+unix]://[host:port]/vdiname[?socket=path][#snapid|#tag] Example @example -qemu-system-i386 --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine +@value{qemu_system} --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine @end example See also @url{https://sheepdog.github.io/sheepdog/}. @@ -365,17 +376,17 @@ JSON: Example @example URI: -qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img, +@value{qemu_system} --drive file=gluster://192.0.2.1/testvol/a.img, @ file.debug=9,file.logfile=/var/log/qemu-gluster.log JSON: -qemu-system-x86_64 'json:@{"driver":"qcow2", +@value{qemu_system} 'json:@{"driver":"qcow2", @ "file":@{"driver":"gluster", @ "volume":"testvol","path":"a.img", @ "debug":9,"logfile":"/var/log/qemu-gluster.log", @ "server":[@{"type":"tcp","host":"1.2.3.4","port":24007@}, @ @{"type":"unix","socket":"/var/run/glusterd.socket"@}]@}@}' -qemu-system-x86_64 -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img, +@value{qemu_system} -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img, @ file.debug=9,file.logfile=/var/log/qemu-gluster.log, @ file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007, @ file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket @@ -440,17 +451,17 @@ of <protocol>. Example: boot from a remote Fedora 20 live ISO image @example -qemu-system-x86_64 --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly +@value{qemu_system_x86} --drive media=cdrom,file=https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly -qemu-system-x86_64 --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly +@value{qemu_system_x86} --drive media=cdrom,file.driver=http,file.url=http://archives.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly @end example Example: boot from a remote Fedora 20 cloud image using a local overlay for writes, copy-on-read, and a readahead of 64k @example -qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2 +qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2 -qemu-system-x86_64 -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on +@value{qemu_system_x86} -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on @end example Example: boot from an image stored on a VMware vSphere server with a self-signed @@ -459,7 +470,7 @@ of 10 seconds. @example qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"https",, "file.url":"https://user:password@@vsphere.example.com/folder/test/test-flat.vmdk?dcPath=Datacenter&dsName=datastore1",, "file.sslverify":"off",, "file.readahead":"64k",, "file.timeout":10@}' /tmp/test.qcow2 -qemu-system-x86_64 -drive file=/tmp/test.qcow2 +@value{qemu_system_x86} -drive file=/tmp/test.qcow2 @end example @end table @@ -826,7 +837,7 @@ On Linux hosts, a shared memory device is available. The basic syntax is: @example -qemu-system-x86_64 -device ivshmem-plain,memdev=@var{hostmem} +@value{qemu_system_x86} -device ivshmem-plain,memdev=@var{hostmem} @end example where @var{hostmem} names a host memory backend. For a POSIX shared @@ -847,7 +858,7 @@ memory server is: ivshmem-server -p @var{pidfile} -S @var{path} -m @var{shm-name} -l @var{shm-size} -n @var{vectors} # Then start your qemu instances with matching arguments -qemu-system-x86_64 -device ivshmem-doorbell,vectors=@var{vectors},chardev=@var{id} +@value{qemu_system_x86} -device ivshmem-doorbell,vectors=@var{vectors},chardev=@var{id} -chardev socket,path=@var{path},id=@var{id} @end example @@ -872,7 +883,7 @@ Instead of specifying the <shm size> using POSIX shm, you may specify a memory backend that has hugepage support: @example -qemu-system-x86_64 -object memory-backend-file,size=1G,mem-path=/dev/hugepages/my-shmem-file,share,id=mb1 +@value{qemu_system_x86} -object memory-backend-file,size=1G,mem-path=/dev/hugepages/my-shmem-file,share,id=mb1 -device ivshmem-plain,memdev=mb1 @end example @@ -888,7 +899,7 @@ kernel testing. The syntax is: @example -qemu-system-i386 -kernel arch/i386/boot/bzImage -hda root-2.4.20.img -append "root=/dev/hda" +@value{qemu_system} -kernel bzImage -hda rootdisk.img -append "root=/dev/hda" @end example Use @option{-kernel} to provide the Linux kernel image and @@ -903,7 +914,7 @@ If you do not need graphical output, you can disable it and redirect the virtual serial port and the QEMU monitor to the console with the @option{-nographic} option. The typical command line is: @example -qemu-system-i386 -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \ +@value{qemu_system} -kernel bzImage -hda rootdisk.img \ -append "root=/dev/hda console=ttyS0" -nographic @end example @@ -969,7 +980,7 @@ Network adapter that supports CDC ethernet and RNDIS protocols. @var{id} specifies a netdev defined with @code{-netdev @dots{},id=@var{id}}. For instance, user-mode networking can be used with @example -qemu-system-i386 [...] -netdev user,id=net0 -device usb-net,netdev=net0 +@value{qemu_system} [...] -netdev user,id=net0 -device usb-net,netdev=net0 @end example @item usb-ccid Smartcard reader device @@ -988,7 +999,7 @@ no type is given, the HCI logic corresponds to @code{-bt hci,vlan=0}. This USB device implements the USB Transport Layer of HCI. Example usage: @example -@command{qemu-system-i386} [...@var{OPTIONS}...] @option{-usbdevice} bt:hci,vlan=3 @option{-bt} device:keyboard,vlan=3 +@command{@value{qemu_system}} [...@var{OPTIONS}...] @option{-usbdevice} bt:hci,vlan=3 @option{-bt} device:keyboard,vlan=3 @end example @end table @@ -1065,7 +1076,7 @@ For this setup it is recommended to restrict it to listen on a UNIX domain socket only. For example @example -qemu-system-i386 [...OPTIONS...] -vnc unix:/home/joebloggs/.qemu-myvm-vnc +@value{qemu_system} [...OPTIONS...] -vnc unix:/home/joebloggs/.qemu-myvm-vnc @end example This ensures that only users on local box with read/write access to that @@ -1088,7 +1099,7 @@ is running the password is set with the monitor. Until the monitor is used to set the password all clients will be rejected. @example -qemu-system-i386 [...OPTIONS...] -vnc :1,password -monitor stdio +@value{qemu_system} [...OPTIONS...] -vnc :1,password -monitor stdio (qemu) change vnc password Password: ******** (qemu) @@ -1105,7 +1116,7 @@ support provides a secure session, but no authentication. This allows any client to connect, and provides an encrypted session. @example -qemu-system-i386 [...OPTIONS...] \ +@value{qemu_system} [...OPTIONS...] \ -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=no \ -vnc :1,tls-creds=tls0 -monitor stdio @end example @@ -1127,7 +1138,7 @@ same syntax as previously, but with @code{verify-peer} set to @code{yes} instead. @example -qemu-system-i386 [...OPTIONS...] \ +@value{qemu_system} [...OPTIONS...] \ -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=yes \ -vnc :1,tls-creds=tls0 -monitor stdio @end example @@ -1140,7 +1151,7 @@ Finally, the previous method can be combined with VNC password authentication to provide two layers of authentication for clients. @example -qemu-system-i386 [...OPTIONS...] \ +@value{qemu_system} [...OPTIONS...] \ -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=yes \ -vnc :1,tls-creds=tls0,password -monitor stdio (qemu) change vnc password @@ -1165,7 +1176,7 @@ used for authentication, but assuming use of one supporting SSF, then QEMU can be launched with: @example -qemu-system-i386 [...OPTIONS...] -vnc :1,sasl -monitor stdio +@value{qemu_system} [...OPTIONS...] -vnc :1,sasl -monitor stdio @end example @node vnc_sec_certificate_sasl @@ -1179,7 +1190,7 @@ credentials. This can be enabled, by combining the 'sasl' option with the aforementioned TLS + x509 options: @example -qemu-system-i386 [...OPTIONS...] \ +@value{qemu_system} [...OPTIONS...] \ -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=yes \ -vnc :1,tls-creds=tls0,sasl -monitor stdio @end example @@ -1512,13 +1523,13 @@ To load server credentials with client certificate validation enabled @example -$QEMU -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server +@value{qemu_system} -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server @end example while to load client credentials use @example -$QEMU -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=client +@value{qemu_system} -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=client @end example Network services which support TLS will all have a @code{tls-creds} @@ -1526,7 +1537,7 @@ parameter which expects the ID of the TLS credentials object. For example with VNC: @example -$QEMU -vnc 0.0.0.0:0,tls-creds=tls0 +@value{qemu_system} -vnc 0.0.0.0:0,tls-creds=tls0 @end example @node tls_psk @@ -1574,8 +1585,7 @@ QEMU has a primitive support to work with gdb, so that you can do In order to use gdb, launch QEMU with the '-s' option. It will wait for a gdb connection: @example -qemu-system-i386 -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \ - -append "root=/dev/hda" +@value{qemu_system} -s -kernel bzImage -hda rootdisk.img -append "root=/dev/hda" Connected to host network interface: tun0 Waiting gdb connection on port 1234 @end example diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 8904733961..d46fa166d3 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -350,6 +350,79 @@ static void qemu_io_free(void *p) qemu_vfree(p); } +/* + * qemu_io_alloc_from_file() + * + * Allocates the buffer and populates it with the content of the given file + * up to @len bytes. If the file length is less than @len, then the buffer + * is populated with the file content cyclically. + * + * @blk - the block backend where the buffer content is going to be written to + * @len - the buffer length + * @file_name - the file to read the content from + * + * Returns: the buffer pointer on success + * NULL on error + */ +static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, + const char *file_name) +{ + char *buf, *buf_origin; + FILE *f = fopen(file_name, "r"); + int pattern_len; + + if (!f) { + perror(file_name); + return NULL; + } + + if (qemuio_misalign) { + len += MISALIGN_OFFSET; + } + + buf_origin = buf = blk_blockalign(blk, len); + + if (qemuio_misalign) { + buf_origin += MISALIGN_OFFSET; + buf += MISALIGN_OFFSET; + len -= MISALIGN_OFFSET; + } + + pattern_len = fread(buf_origin, 1, len, f); + + if (ferror(f)) { + perror(file_name); + goto error; + } + + if (pattern_len == 0) { + fprintf(stderr, "%s: file is empty\n", file_name); + goto error; + } + + fclose(f); + + if (len > pattern_len) { + len -= pattern_len; + buf += pattern_len; + + while (len > 0) { + size_t len_to_copy = MIN(pattern_len, len); + + memcpy(buf, buf_origin, len_to_copy); + + len -= len_to_copy; + buf += len_to_copy; + } + } + + return buf_origin; + +error: + qemu_io_free(buf_origin); + return NULL; +} + static void dump_buffer(const void *buffer, int64_t offset, int64_t len) { uint64_t i; @@ -948,6 +1021,7 @@ static void write_help(void) " -n, -- with -z, don't allow slow fallback\n" " -p, -- ignored for backwards compatibility\n" " -P, -- use different pattern to fill file\n" +" -s, -- use a pattern file to fill the write buffer\n" " -C, -- report statistics in a machine parsable format\n" " -q, -- quiet mode, do not show I/O statistics\n" " -u, -- with -z, allow unmapping\n" @@ -964,7 +1038,7 @@ static const cmdinfo_t write_cmd = { .perm = BLK_PERM_WRITE, .argmin = 2, .argmax = -1, - .args = "[-bcCfnquz] [-P pattern] off len", + .args = "[-bcCfnquz] [-P pattern | -s source_file] off len", .oneline = "writes a number of bytes at a specified offset", .help = write_help, }; @@ -973,7 +1047,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv) { struct timespec t1, t2; bool Cflag = false, qflag = false, bflag = false; - bool Pflag = false, zflag = false, cflag = false; + bool Pflag = false, zflag = false, cflag = false, sflag = false; int flags = 0; int c, cnt, ret; char *buf = NULL; @@ -982,8 +1056,9 @@ static int write_f(BlockBackend *blk, int argc, char **argv) /* Some compilers get confused and warn if this is not initialized. */ int64_t total = 0; int pattern = 0xcd; + const char *file_name = NULL; - while ((c = getopt(argc, argv, "bcCfnpP:quz")) != -1) { + while ((c = getopt(argc, argv, "bcCfnpP:qs:uz")) != -1) { switch (c) { case 'b': bflag = true; @@ -1013,6 +1088,10 @@ static int write_f(BlockBackend *blk, int argc, char **argv) case 'q': qflag = true; break; + case 's': + sflag = true; + file_name = optarg; + break; case 'u': flags |= BDRV_REQ_MAY_UNMAP; break; @@ -1050,8 +1129,9 @@ static int write_f(BlockBackend *blk, int argc, char **argv) return -EINVAL; } - if (zflag && Pflag) { - printf("-z and -P cannot be specified at the same time\n"); + if (zflag + Pflag + sflag > 1) { + printf("Only one of -z, -P, and -s " + "can be specified at the same time\n"); return -EINVAL; } @@ -1087,7 +1167,14 @@ static int write_f(BlockBackend *blk, int argc, char **argv) } if (!zflag) { - buf = qemu_io_alloc(blk, count, pattern); + if (sflag) { + buf = qemu_io_alloc_from_file(blk, count, file_name); + if (!buf) { + return -EINVAL; + } + } else { + buf = qemu_io_alloc(blk, count, pattern); + } } clock_gettime(CLOCK_MONOTONIC, &t1); diff --git a/qemu-nbd.c b/qemu-nbd.c index 049645491d..9032b6de2a 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -294,6 +294,7 @@ static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls, [NBD_FLAG_CAN_MULTI_CONN_BIT] = "multi", [NBD_FLAG_SEND_RESIZE_BIT] = "resize", [NBD_FLAG_SEND_CACHE_BIT] = "cache", + [NBD_FLAG_SEND_FAST_ZERO_BIT] = "fast-zero", }; printf(" size: %" PRIu64 "\n", list[i].size); @@ -600,7 +601,7 @@ int main(int argc, char **argv) BlockBackend *blk; BlockDriverState *bs; uint64_t dev_offset = 0; - uint16_t nbdflags = 0; + bool readonly = false; bool disconnect = false; const char *bindto = NULL; const char *port = NULL; @@ -782,7 +783,7 @@ int main(int argc, char **argv) } /* fall through */ case 'r': - nbdflags |= NBD_FLAG_READ_ONLY; + readonly = true; flags &= ~BDRV_O_RDWR; break; case 'P': @@ -1054,7 +1055,7 @@ int main(int argc, char **argv) server = qio_net_listener_new(); if (socket_activation == 0) { saddr = nbd_build_socket_address(sockpath, bindto, port); - if (qio_net_listener_open_sync(server, saddr, &local_err) < 0) { + if (qio_net_listener_open_sync(server, saddr, 1, &local_err) < 0) { object_unref(OBJECT(server)); error_report_err(local_err); exit(EXIT_FAILURE); @@ -1173,7 +1174,7 @@ int main(int argc, char **argv) } export = nbd_export_new(bs, dev_offset, fd_size, export_name, - export_description, bitmap, nbdflags, + export_description, bitmap, readonly, shared > 1, nbd_export_closed, writethrough, NULL, &error_fatal); diff --git a/qemu-options.hx b/qemu-options.hx index ea0638e92d..bbfd936d29 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -254,10 +254,10 @@ This option defines a free-form string that can be used to describe @var{fd}. You can open an image using pre-opened file descriptors from an fd set: @example -qemu-system-i386 --add-fd fd=3,set=2,opaque="rdwr:/path/to/file" --add-fd fd=4,set=2,opaque="rdonly:/path/to/file" --drive file=/dev/fdset/2,index=0,media=disk +@value{qemu_system} \ + -add-fd fd=3,set=2,opaque="rdwr:/path/to/file" \ + -add-fd fd=4,set=2,opaque="rdonly:/path/to/file" \ + -drive file=/dev/fdset/2,index=0,media=disk @end example ETEXI @@ -283,7 +283,7 @@ STEXI Set default value of @var{driver}'s property @var{prop} to @var{value}, e.g.: @example -qemu-system-i386 -global ide-hd.physical_block_size=4096 disk-image.img +@value{qemu_system_x86} -global ide-hd.physical_block_size=4096 disk-image.img @end example In particular, you can use this to set driver properties for devices which are @@ -337,11 +337,11 @@ bootindex options. The default is non-strict boot. @example # try to boot from network first, then from hard disk -qemu-system-i386 -boot order=nc +@value{qemu_system_x86} -boot order=nc # boot from CD-ROM first, switch back to default order after reboot -qemu-system-i386 -boot once=d +@value{qemu_system_x86} -boot once=d # boot with a splash picture for 5 seconds. -qemu-system-i386 -boot menu=on,splash=/root/boot.bmp,splash-time=5000 +@value{qemu_system_x86} -boot menu=on,splash=/root/boot.bmp,splash-time=5000 @end example Note: The legacy format '-boot @var{drives}' is still supported but its @@ -370,7 +370,7 @@ For example, the following command-line sets the guest startup RAM size to memory the guest can reach to 4GB: @example -qemu-system-x86_64 -m 1G,slots=3,maxmem=4G +@value{qemu_system} -m 1G,slots=3,maxmem=4G @end example If @var{slots} and @var{maxmem} are not specified, memory hotplug won't @@ -666,15 +666,15 @@ STEXI @item -soundhw @var{card1}[,@var{card2},...] or -soundhw all @findex -soundhw Enable audio and selected sound hardware. Use 'help' to print all -available sound hardware. +available sound hardware. For example: @example -qemu-system-i386 -soundhw sb16,adlib disk.img -qemu-system-i386 -soundhw es1370 disk.img -qemu-system-i386 -soundhw ac97 disk.img -qemu-system-i386 -soundhw hda disk.img -qemu-system-i386 -soundhw all disk.img -qemu-system-i386 -soundhw help +@value{qemu_system_x86} -soundhw sb16,adlib disk.img +@value{qemu_system_x86} -soundhw es1370 disk.img +@value{qemu_system_x86} -soundhw ac97 disk.img +@value{qemu_system_x86} -soundhw hda disk.img +@value{qemu_system_x86} -soundhw all disk.img +@value{qemu_system_x86} -soundhw help @end example Note that Linux's i810_audio OSS kernel (for AC97) module might @@ -1149,50 +1149,50 @@ is off. Instead of @option{-cdrom} you can use: @example -qemu-system-i386 -drive file=file,index=2,media=cdrom +@value{qemu_system} -drive file=file,index=2,media=cdrom @end example Instead of @option{-hda}, @option{-hdb}, @option{-hdc}, @option{-hdd}, you can use: @example -qemu-system-i386 -drive file=file,index=0,media=disk -qemu-system-i386 -drive file=file,index=1,media=disk -qemu-system-i386 -drive file=file,index=2,media=disk -qemu-system-i386 -drive file=file,index=3,media=disk +@value{qemu_system} -drive file=file,index=0,media=disk +@value{qemu_system} -drive file=file,index=1,media=disk +@value{qemu_system} -drive file=file,index=2,media=disk +@value{qemu_system} -drive file=file,index=3,media=disk @end example You can open an image using pre-opened file descriptors from an fd set: @example -qemu-system-i386 --add-fd fd=3,set=2,opaque="rdwr:/path/to/file" --add-fd fd=4,set=2,opaque="rdonly:/path/to/file" --drive file=/dev/fdset/2,index=0,media=disk +@value{qemu_system} \ + -add-fd fd=3,set=2,opaque="rdwr:/path/to/file" \ + -add-fd fd=4,set=2,opaque="rdonly:/path/to/file" \ + -drive file=/dev/fdset/2,index=0,media=disk @end example You can connect a CDROM to the slave of ide0: @example -qemu-system-i386 -drive file=file,if=ide,index=1,media=cdrom +@value{qemu_system_x86} -drive file=file,if=ide,index=1,media=cdrom @end example If you don't specify the "file=" argument, you define an empty drive: @example -qemu-system-i386 -drive if=ide,index=1,media=cdrom +@value{qemu_system_x86} -drive if=ide,index=1,media=cdrom @end example Instead of @option{-fda}, @option{-fdb}, you can use: @example -qemu-system-i386 -drive file=file,index=0,if=floppy -qemu-system-i386 -drive file=file,index=1,if=floppy +@value{qemu_system_x86} -drive file=file,index=0,if=floppy +@value{qemu_system_x86} -drive file=file,index=1,if=floppy @end example By default, @var{interface} is "ide" and @var{index} is automatically incremented: @example -qemu-system-i386 -drive file=a -drive file=b" +@value{qemu_system_x86} -drive file=a -drive file=b" @end example is interpreted like: @example -qemu-system-i386 -hda a -hdb b +@value{qemu_system_x86} -hda a -hdb b @end example ETEXI @@ -2272,8 +2272,8 @@ The following two example do exactly the same, to show how @option{-nic} can be used to shorten the command line length (note that the e1000 is the default on i386, so the @option{model=e1000} parameter could even be omitted here, too): @example -qemu-system-i386 -netdev user,id=n1,ipv6=off -device e1000,netdev=n1,mac=52:54:98:76:54:32 -qemu-system-i386 -nic user,ipv6=off,model=e1000,mac=52:54:98:76:54:32 +@value{qemu_system} -netdev user,id=n1,ipv6=off -device e1000,netdev=n1,mac=52:54:98:76:54:32 +@value{qemu_system} -nic user,ipv6=off,model=e1000,mac=52:54:98:76:54:32 @end example @item -nic none @@ -2344,7 +2344,7 @@ can not be resolved. Example: @example -qemu-system-i386 -nic user,dnssearch=mgmt.example.org,dnssearch=example.org +@value{qemu_system} -nic user,dnssearch=mgmt.example.org,dnssearch=example.org @end example @item domainname=@var{domain} @@ -2368,7 +2368,7 @@ a guest from a local directory. Example (using pxelinux): @example -qemu-system-i386 -hda linux.img -boot n -device e1000,netdev=n1 \ +@value{qemu_system} -hda linux.img -boot n -device e1000,netdev=n1 \ -netdev user,id=n1,tftp=/path/to/tftp/files,bootfile=/pxelinux.0 @end example @@ -2402,7 +2402,7 @@ screen 0, use the following: @example # on the host -qemu-system-i386 -nic user,hostfwd=tcp:127.0.0.1:6001-:6000 +@value{qemu_system} -nic user,hostfwd=tcp:127.0.0.1:6001-:6000 # this host xterm should open in the guest X11 server xterm -display :1 @end example @@ -2412,7 +2412,7 @@ the guest, use the following: @example # on the host -qemu-system-i386 -nic user,hostfwd=tcp::5555-:23 +@value{qemu_system} -nic user,hostfwd=tcp::5555-:23 telnet localhost 5555 @end example @@ -2431,7 +2431,7 @@ lifetime, like in the following example: @example # open 10.10.1.1:4321 on bootup, connect 10.0.2.100:1234 to it whenever # the guest accesses it -qemu-system-i386 -nic user,guestfwd=tcp:10.0.2.100:1234-tcp:10.10.1.1:4321 +@value{qemu_system} -nic user,guestfwd=tcp:10.0.2.100:1234-tcp:10.10.1.1:4321 @end example Or you can execute a command on every TCP connection established by the guest, @@ -2440,7 +2440,7 @@ so that QEMU behaves similar to an inetd process for that virtual server: @example # call "netcat 10.10.1.1 4321" on every TCP connection to 10.0.2.100:1234 # and connect the TCP stream to its stdin/stdout -qemu-system-i386 -nic 'user,id=n1,guestfwd=tcp:10.0.2.100:1234-cmd:netcat 10.10.1.1 4321' +@value{qemu_system} -nic 'user,id=n1,guestfwd=tcp:10.0.2.100:1234-cmd:netcat 10.10.1.1 4321' @end example @end table @@ -2467,13 +2467,13 @@ Examples: @example #launch a QEMU instance with the default network script -qemu-system-i386 linux.img -nic tap +@value{qemu_system} linux.img -nic tap @end example @example #launch a QEMU instance with two NICs, each one connected #to a TAP device -qemu-system-i386 linux.img \ +@value{qemu_system} linux.img \ -netdev tap,id=nd0,ifname=tap0 -device e1000,netdev=nd0 \ -netdev tap,id=nd1,ifname=tap1 -device rtl8139,netdev=nd1 @end example @@ -2481,7 +2481,7 @@ qemu-system-i386 linux.img \ @example #launch a QEMU instance with the default network helper to #connect a TAP device to bridge br0 -qemu-system-i386 linux.img -device virtio-net-pci,netdev=n1 \ +@value{qemu_system} linux.img -device virtio-net-pci,netdev=n1 \ -netdev tap,id=n1,"helper=/path/to/qemu-bridge-helper" @end example @@ -2498,13 +2498,13 @@ Examples: @example #launch a QEMU instance with the default network helper to #connect a TAP device to bridge br0 -qemu-system-i386 linux.img -netdev bridge,id=n1 -device virtio-net,netdev=n1 +@value{qemu_system} linux.img -netdev bridge,id=n1 -device virtio-net,netdev=n1 @end example @example #launch a QEMU instance with the default network helper to #connect a TAP device to bridge qemubr0 -qemu-system-i386 linux.img -netdev bridge,br=qemubr0,id=n1 -device virtio-net,netdev=n1 +@value{qemu_system} linux.img -netdev bridge,br=qemubr0,id=n1 -device virtio-net,netdev=n1 @end example @item -netdev socket,id=@var{id}[,fd=@var{h}][,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}] @@ -2519,11 +2519,11 @@ specifies an already opened TCP socket. Example: @example # launch a first QEMU instance -qemu-system-i386 linux.img \ +@value{qemu_system} linux.img \ -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ -netdev socket,id=n1,listen=:1234 # connect the network of this instance to the network of the first instance -qemu-system-i386 linux.img \ +@value{qemu_system} linux.img \ -device e1000,netdev=n2,mac=52:54:00:12:34:57 \ -netdev socket,id=n2,connect=127.0.0.1:1234 @end example @@ -2548,15 +2548,15 @@ Use @option{fd=h} to specify an already opened UDP multicast socket. Example: @example # launch one QEMU instance -qemu-system-i386 linux.img \ +@value{qemu_system} linux.img \ -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ -netdev socket,id=n1,mcast=230.0.0.1:1234 # launch another QEMU instance on same "bus" -qemu-system-i386 linux.img \ +@value{qemu_system} linux.img \ -device e1000,netdev=n2,mac=52:54:00:12:34:57 \ -netdev socket,id=n2,mcast=230.0.0.1:1234 # launch yet another QEMU instance on same "bus" -qemu-system-i386 linux.img \ +@value{qemu_system} linux.img \ -device e1000,netdev=n3,mac=52:54:00:12:34:58 \ -netdev socket,id=n3,mcast=230.0.0.1:1234 @end example @@ -2564,7 +2564,7 @@ qemu-system-i386 linux.img \ Example (User Mode Linux compat.): @example # launch QEMU instance (note mcast address selected is UML's default) -qemu-system-i386 linux.img \ +@value{qemu_system} linux.img \ -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ -netdev socket,id=n1,mcast=239.192.168.1:1102 # launch UML @@ -2573,7 +2573,7 @@ qemu-system-i386 linux.img \ Example (send packets from host's 1.2.3.4): @example -qemu-system-i386 linux.img \ +@value{qemu_system} linux.img \ -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ -netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4 @end example @@ -2633,7 +2633,7 @@ brctl addif br-lan vmtunnel0 # on 4.3.2.1 # launch QEMU instance - if your network has reorder or is very lossy add ,pincounter -qemu-system-i386 linux.img -device e1000,netdev=n1 \ +@value{qemu_system} linux.img -device e1000,netdev=n1 \ -netdev l2tpv3,id=n1,src=4.2.3.1,dst=1.2.3.4,udp,srcport=16384,dstport=16384,rxsession=0xffffffff,txsession=0xffffffff,counter @end example @@ -2650,7 +2650,7 @@ Example: # launch vde switch vde_switch -F -sock /tmp/myswitch # launch QEMU instance -qemu-system-i386 linux.img -nic vde,sock=/tmp/myswitch +@value{qemu_system} linux.img -nic vde,sock=/tmp/myswitch @end example @item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off][,queues=n] @@ -3107,7 +3107,7 @@ and communicate. Requires the Linux @code{vhci} driver installed. Can be used as following: @example -qemu-system-i386 [...OPTIONS...] -bt hci,vlan=5 -bt vhci,vlan=5 +@value{qemu_system} [...OPTIONS...] -bt hci,vlan=5 -bt vhci,vlan=5 @end example @item -bt device:@var{dev}[,vlan=@var{n}] @@ -3601,7 +3601,7 @@ connections will likely be TCP-based, but also UDP, pseudo TTY, or even stdio are reasonable use case. The latter is allowing to start QEMU from within gdb and establish the connection via a pipe: @example -(gdb) target remote | exec qemu-system-i386 -gdb stdio ... +(gdb) target remote | exec @value{qemu_system} -gdb stdio ... @end example ETEXI @@ -4332,6 +4332,13 @@ other options. The @option{share} boolean option is @var{on} by default with memfd. +@item -object rng-builtin,id=@var{id} + +Creates a random number generator backend which obtains entropy from +QEMU builtin functions. The @option{id} parameter is a unique ID that +will be used to reference this entropy backend from the @option{virtio-rng} +device. By default, the @option{virtio-rng} device uses this RNG backend. + @item -object rng-random,id=@var{id},filename=@var{/dev/random} Creates a random number generator backend which obtains entropy from @@ -4571,7 +4578,7 @@ which specify the queue number of cryptodev backend, the default of @example - # qemu-system-x86_64 \ + # @value{qemu_system} \ [...] \ -object cryptodev-backend-builtin,id=cryptodev0 \ -device virtio-crypto-pci,id=crypto0,cryptodev=cryptodev0 \ @@ -4591,7 +4598,7 @@ of cryptodev backend for multiqueue vhost-user, the default of @var{queues} is 1 @example - # qemu-system-x86_64 \ + # @value{qemu_system} \ [...] \ -chardev socket,id=chardev0,path=/path/to/socket \ -object cryptodev-vhost-user,id=cryptodev0,chardev=chardev0 \ @@ -4627,14 +4634,14 @@ The simplest (insecure) usage is to provide the secret inline @example - # $QEMU -object secret,id=sec0,data=letmein,format=raw + # @value{qemu_system} -object secret,id=sec0,data=letmein,format=raw @end example The simplest secure usage is to provide the secret via a file # printf "letmein" > mypasswd.txt - # $QEMU -object secret,id=sec0,file=mypasswd.txt,format=raw + # @value{qemu_system} -object secret,id=sec0,file=mypasswd.txt,format=raw For greater security, AES-256-CBC should be used. To illustrate usage, consider the openssl command line tool which can encrypt the data. Note @@ -4670,7 +4677,7 @@ and specify that to be used to decrypt the user password. Pass the contents of @code{iv.b64} to the second secret @example - # $QEMU \ + # @value{qemu_system} \ -object secret,id=secmaster0,format=base64,file=key.b64 \ -object secret,id=sec0,keyid=secmaster0,format=base64,\ data=$SECRET,iv=$(<iv.b64) @@ -4713,7 +4720,7 @@ negotiate keys used for attestation. The file must be encoded in base64. e.g to launch a SEV guest @example - # $QEMU \ + # @value{qemu_system_x86} \ ...... -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=5 \ -machine ...,memory-encryption=sev0 @@ -4735,7 +4742,7 @@ any commas in the distinguished name. An example authorization object to validate a x509 distinguished name would look like: @example - # $QEMU \ + # @value{qemu_system} \ ... -object 'authz-simple,id=auth0,identity=CN=laptop.example.com,,O=Example Org,,L=London,,ST=London,,C=GB' \ ... @@ -4784,7 +4791,7 @@ a TLS x509 distinguished name, or a SASL username. An example authorization object to validate a SASL username would look like: @example - # $QEMU \ + # @value{qemu_system} \ ... -object authz-simple,id=auth0,filename=/etc/qemu/vnc-sasl.acl,refresh=yes ... @@ -4802,7 +4809,7 @@ An example authorization object to validate a TLS x509 distinguished name would look like: @example - # $QEMU \ + # @value{qemu_system} \ ... -object authz-pam,id=auth0,service=qemu-vnc ... diff --git a/qga/channel-posix.c b/qga/channel-posix.c index 5a925a9818..8fc205ad21 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -215,7 +215,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, return false; } - fd = socket_listen(addr, &local_err); + fd = socket_listen(addr, 1, &local_err); qapi_free_SocketAddress(addr); if (local_err != NULL) { g_critical("%s", error_get_pretty(local_err)); diff --git a/roms/SLOF b/roms/SLOF -Subproject 7bfe584e321946771692711ff83ad2b5850daca +Subproject ea221600a116883137ef90b2b7ab7d2472bc4f1 diff --git a/roms/skiboot b/roms/skiboot -Subproject 261ca8e779e5138869a45f174caa49be6a27450 +Subproject 3a6fdede6ce117facec0108afe716cf5d0472c3 diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d24c9441ee..aa9a354a0e 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -461,7 +461,7 @@ sub top_of_kernel_tree { my @tree_check = ( "COPYING", "MAINTAINERS", "Makefile", - "README", "docs", "VERSION", + "README.rst", "docs", "VERSION", "vl.c" ); diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index a256ce490b..a8a74d1dba 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -1005,7 +1005,8 @@ int main(int argc, char **argv) .u.q_unix.path = socket_path, }; server_ioc = qio_channel_socket_new(); - if (qio_channel_socket_listen_sync(server_ioc, &saddr, &local_err) < 0) { + if (qio_channel_socket_listen_sync(server_ioc, &saddr, + 1, &local_err) < 0) { object_unref(OBJECT(server_ioc)); error_report_err(local_err); return 1; diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 1e29653aac..a69f58bf65 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -403,7 +403,7 @@ static inline void gen_store_mem(DisasContext *ctx, static DisasJumpType gen_store_conditional(DisasContext *ctx, int ra, int rb, int32_t disp16, int mem_idx, - TCGMemOp op) + MemOp op) { TCGLabel *lab_fail, *lab_done; TCGv addr, val; diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs index 5cafc1eb6c..cf26c16f5f 100644 --- a/target/arm/Makefile.objs +++ b/target/arm/Makefile.objs @@ -28,9 +28,33 @@ target/arm/decode-vfp-uncond.inc.c: $(SRC_PATH)/target/arm/vfp-uncond.decode $(D $(PYTHON) $(DECODETREE) --static-decode disas_vfp_uncond -o $@ $<,\ "GEN", $(TARGET_DIR)$@) +target/arm/decode-a32.inc.c: $(SRC_PATH)/target/arm/a32.decode $(DECODETREE) + $(call quiet-command,\ + $(PYTHON) $(DECODETREE) --static-decode disas_a32 -o $@ $<,\ + "GEN", $(TARGET_DIR)$@) + +target/arm/decode-a32-uncond.inc.c: $(SRC_PATH)/target/arm/a32-uncond.decode $(DECODETREE) + $(call quiet-command,\ + $(PYTHON) $(DECODETREE) --static-decode disas_a32_uncond -o $@ $<,\ + "GEN", $(TARGET_DIR)$@) + +target/arm/decode-t32.inc.c: $(SRC_PATH)/target/arm/t32.decode $(DECODETREE) + $(call quiet-command,\ + $(PYTHON) $(DECODETREE) --static-decode disas_t32 -o $@ $<,\ + "GEN", $(TARGET_DIR)$@) + +target/arm/decode-t16.inc.c: $(SRC_PATH)/target/arm/t16.decode $(DECODETREE) + $(call quiet-command,\ + $(PYTHON) $(DECODETREE) -w 16 --static-decode disas_t16 -o $@ $<,\ + "GEN", $(TARGET_DIR)$@) + target/arm/translate-sve.o: target/arm/decode-sve.inc.c target/arm/translate.o: target/arm/decode-vfp.inc.c target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c +target/arm/translate.o: target/arm/decode-a32.inc.c +target/arm/translate.o: target/arm/decode-a32-uncond.inc.c +target/arm/translate.o: target/arm/decode-t32.inc.c +target/arm/translate.o: target/arm/decode-t16.inc.c obj-y += tlb_helper.o debug_helper.o obj-y += translate.o op_helper.o diff --git a/target/arm/a32-uncond.decode b/target/arm/a32-uncond.decode new file mode 100644 index 0000000000..60ccfc598d --- /dev/null +++ b/target/arm/a32-uncond.decode @@ -0,0 +1,74 @@ +# A32 unconditional instructions +# +# Copyright (c) 2019 Linaro, Ltd +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. + +# +# This file is processed by scripts/decodetree.py +# +# All insns that have 0xf in insn[31:28] are decoded here. +# All of those that have a COND field in insn[31:28] are in a32.decode +# + +&empty !extern +&i !extern imm +&setend E + +# Branch with Link and Exchange + +%imm24h 0:s24 24:1 !function=times_2 + +BLX_i 1111 101 . ........................ &i imm=%imm24h + +# System Instructions + +&rfe rn w pu +&srs mode w pu +&cps mode imod M A I F + +RFE 1111 100 pu:2 0 w:1 1 rn:4 0000 1010 0000 0000 &rfe +SRS 1111 100 pu:2 1 w:1 0 1101 0000 0101 000 mode:5 &srs +CPS 1111 0001 0000 imod:2 M:1 0 0000 000 A:1 I:1 F:1 0 mode:5 \ + &cps + +# Clear-Exclusive, Barriers + +# QEMU does not require the option field for the barriers. +CLREX 1111 0101 0111 1111 1111 0000 0001 1111 +DSB 1111 0101 0111 1111 1111 0000 0100 ---- +DMB 1111 0101 0111 1111 1111 0000 0101 ---- +ISB 1111 0101 0111 1111 1111 0000 0110 ---- +SB 1111 0101 0111 1111 1111 0000 0111 0000 + +# Set Endianness +SETEND 1111 0001 0000 0001 0000 00 E:1 0 0000 0000 &setend + +# Preload instructions + +PLD 1111 0101 -101 ---- 1111 ---- ---- ---- # (imm, lit) 5te +PLDW 1111 0101 -001 ---- 1111 ---- ---- ---- # (imm, lit) 7mp +PLI 1111 0100 -101 ---- 1111 ---- ---- ---- # (imm, lit) 7 + +PLD 1111 0111 -101 ---- 1111 ----- -- 0 ---- # (register) 5te +PLDW 1111 0111 -001 ---- 1111 ----- -- 0 ---- # (register) 7mp +PLI 1111 0110 -101 ---- 1111 ----- -- 0 ---- # (register) 7 + +# Unallocated memory hints +# +# Since these are v7MP nops, and PLDW is v7MP and implemented as nop, +# (ab)use the PLDW helper. + +PLDW 1111 0100 -001 ---- ---- ---- ---- ---- +PLDW 1111 0110 -001 ---- ---- ---- ---0 ---- diff --git a/target/arm/a32.decode b/target/arm/a32.decode new file mode 100644 index 0000000000..0bd952c069 --- /dev/null +++ b/target/arm/a32.decode @@ -0,0 +1,534 @@ +# A32 conditional instructions +# +# Copyright (c) 2019 Linaro, Ltd +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. + +# +# This file is processed by scripts/decodetree.py +# +# All of the insn that have a COND field in insn[31:28] are here. +# All insns that have 0xf in insn[31:28] are in a32-uncond.decode. +# + +&empty +&s_rrr_shi s rd rn rm shim shty +&s_rrr_shr s rn rd rm rs shty +&s_rri_rot s rn rd imm rot +&s_rrrr s rd rn rm ra +&rrrr rd rn rm ra +&rrr_rot rd rn rm rot +&rrr rd rn rm +&rr rd rm +&ri rd imm +&r rm +&i imm +&msr_reg rn r mask +&mrs_reg rd r +&msr_bank rn r sysm +&mrs_bank rd r sysm +&ldst_rr p w u rn rt rm shimm shtype +&ldst_ri p w u rn rt imm +&ldst_block rn i b u w list +&strex rn rd rt rt2 imm +&ldrex rn rt rt2 imm +&bfx rd rn lsb widthm1 +&bfi rd rn lsb msb +&sat rd rn satimm imm sh +&pkh rd rn rm imm tb + +# Data-processing (register) + +@s_rrr_shi ---- ... .... s:1 rn:4 rd:4 shim:5 shty:2 . rm:4 \ + &s_rrr_shi +@s_rxr_shi ---- ... .... s:1 .... rd:4 shim:5 shty:2 . rm:4 \ + &s_rrr_shi rn=0 +@S_xrr_shi ---- ... .... . rn:4 .... shim:5 shty:2 . rm:4 \ + &s_rrr_shi s=1 rd=0 + +AND_rrri .... 000 0000 . .... .... ..... .. 0 .... @s_rrr_shi +EOR_rrri .... 000 0001 . .... .... ..... .. 0 .... @s_rrr_shi +SUB_rrri .... 000 0010 . .... .... ..... .. 0 .... @s_rrr_shi +RSB_rrri .... 000 0011 . .... .... ..... .. 0 .... @s_rrr_shi +ADD_rrri .... 000 0100 . .... .... ..... .. 0 .... @s_rrr_shi +ADC_rrri .... 000 0101 . .... .... ..... .. 0 .... @s_rrr_shi +SBC_rrri .... 000 0110 . .... .... ..... .. 0 .... @s_rrr_shi +RSC_rrri .... 000 0111 . .... .... ..... .. 0 .... @s_rrr_shi +TST_xrri .... 000 1000 1 .... 0000 ..... .. 0 .... @S_xrr_shi +TEQ_xrri .... 000 1001 1 .... 0000 ..... .. 0 .... @S_xrr_shi +CMP_xrri .... 000 1010 1 .... 0000 ..... .. 0 .... @S_xrr_shi +CMN_xrri .... 000 1011 1 .... 0000 ..... .. 0 .... @S_xrr_shi +ORR_rrri .... 000 1100 . .... .... ..... .. 0 .... @s_rrr_shi +MOV_rxri .... 000 1101 . 0000 .... ..... .. 0 .... @s_rxr_shi +BIC_rrri .... 000 1110 . .... .... ..... .. 0 .... @s_rrr_shi +MVN_rxri .... 000 1111 . 0000 .... ..... .. 0 .... @s_rxr_shi + +%imm16 16:4 0:12 +@mov16 ---- .... .... .... rd:4 ............ &ri imm=%imm16 + +MOVW .... 0011 0000 .... .... ............ @mov16 +MOVT .... 0011 0100 .... .... ............ @mov16 + +# Data-processing (register-shifted register) + +@s_rrr_shr ---- ... .... s:1 rn:4 rd:4 rs:4 . shty:2 . rm:4 \ + &s_rrr_shr +@s_rxr_shr ---- ... .... s:1 .... rd:4 rs:4 . shty:2 . rm:4 \ + &s_rrr_shr rn=0 +@S_xrr_shr ---- ... .... . rn:4 .... rs:4 . shty:2 . rm:4 \ + &s_rrr_shr rd=0 s=1 + +AND_rrrr .... 000 0000 . .... .... .... 0 .. 1 .... @s_rrr_shr +EOR_rrrr .... 000 0001 . .... .... .... 0 .. 1 .... @s_rrr_shr +SUB_rrrr .... 000 0010 . .... .... .... 0 .. 1 .... @s_rrr_shr +RSB_rrrr .... 000 0011 . .... .... .... 0 .. 1 .... @s_rrr_shr +ADD_rrrr .... 000 0100 . .... .... .... 0 .. 1 .... @s_rrr_shr +ADC_rrrr .... 000 0101 . .... .... .... 0 .. 1 .... @s_rrr_shr +SBC_rrrr .... 000 0110 . .... .... .... 0 .. 1 .... @s_rrr_shr +RSC_rrrr .... 000 0111 . .... .... .... 0 .. 1 .... @s_rrr_shr +TST_xrrr .... 000 1000 1 .... 0000 .... 0 .. 1 .... @S_xrr_shr +TEQ_xrrr .... 000 1001 1 .... 0000 .... 0 .. 1 .... @S_xrr_shr +CMP_xrrr .... 000 1010 1 .... 0000 .... 0 .. 1 .... @S_xrr_shr +CMN_xrrr .... 000 1011 1 .... 0000 .... 0 .. 1 .... @S_xrr_shr +ORR_rrrr .... 000 1100 . .... .... .... 0 .. 1 .... @s_rrr_shr +MOV_rxrr .... 000 1101 . 0000 .... .... 0 .. 1 .... @s_rxr_shr +BIC_rrrr .... 000 1110 . .... .... .... 0 .. 1 .... @s_rrr_shr +MVN_rxrr .... 000 1111 . 0000 .... .... 0 .. 1 .... @s_rxr_shr + +# Data-processing (immediate) + +%a32extrot 8:4 !function=times_2 + +@s_rri_rot ---- ... .... s:1 rn:4 rd:4 .... imm:8 \ + &s_rri_rot rot=%a32extrot +@s_rxi_rot ---- ... .... s:1 .... rd:4 .... imm:8 \ + &s_rri_rot rot=%a32extrot rn=0 +@S_xri_rot ---- ... .... . rn:4 .... .... imm:8 \ + &s_rri_rot rot=%a32extrot rd=0 s=1 + +AND_rri .... 001 0000 . .... .... ............ @s_rri_rot +EOR_rri .... 001 0001 . .... .... ............ @s_rri_rot +SUB_rri .... 001 0010 . .... .... ............ @s_rri_rot +RSB_rri .... 001 0011 . .... .... ............ @s_rri_rot +ADD_rri .... 001 0100 . .... .... ............ @s_rri_rot +ADC_rri .... 001 0101 . .... .... ............ @s_rri_rot +SBC_rri .... 001 0110 . .... .... ............ @s_rri_rot +RSC_rri .... 001 0111 . .... .... ............ @s_rri_rot +TST_xri .... 001 1000 1 .... 0000 ............ @S_xri_rot +TEQ_xri .... 001 1001 1 .... 0000 ............ @S_xri_rot +CMP_xri .... 001 1010 1 .... 0000 ............ @S_xri_rot +CMN_xri .... 001 1011 1 .... 0000 ............ @S_xri_rot +ORR_rri .... 001 1100 . .... .... ............ @s_rri_rot +MOV_rxi .... 001 1101 . 0000 .... ............ @s_rxi_rot +BIC_rri .... 001 1110 . .... .... ............ @s_rri_rot +MVN_rxi .... 001 1111 . 0000 .... ............ @s_rxi_rot + +# Multiply and multiply accumulate + +@s_rdamn ---- .... ... s:1 rd:4 ra:4 rm:4 .... rn:4 &s_rrrr +@s_rd0mn ---- .... ... s:1 rd:4 .... rm:4 .... rn:4 &s_rrrr ra=0 +@rdamn ---- .... ... . rd:4 ra:4 rm:4 .... rn:4 &rrrr +@rd0mn ---- .... ... . rd:4 .... rm:4 .... rn:4 &rrrr ra=0 + +MUL .... 0000 000 . .... 0000 .... 1001 .... @s_rd0mn +MLA .... 0000 001 . .... .... .... 1001 .... @s_rdamn +UMAAL .... 0000 010 0 .... .... .... 1001 .... @rdamn +MLS .... 0000 011 0 .... .... .... 1001 .... @rdamn +UMULL .... 0000 100 . .... .... .... 1001 .... @s_rdamn +UMLAL .... 0000 101 . .... .... .... 1001 .... @s_rdamn +SMULL .... 0000 110 . .... .... .... 1001 .... @s_rdamn +SMLAL .... 0000 111 . .... .... .... 1001 .... @s_rdamn + +# Saturating addition and subtraction + +@rndm ---- .... .... rn:4 rd:4 .... .... rm:4 &rrr + +QADD .... 0001 0000 .... .... 0000 0101 .... @rndm +QSUB .... 0001 0010 .... .... 0000 0101 .... @rndm +QDADD .... 0001 0100 .... .... 0000 0101 .... @rndm +QDSUB .... 0001 0110 .... .... 0000 0101 .... @rndm + +# Halfword multiply and multiply accumulate + +SMLABB .... 0001 0000 .... .... .... 1000 .... @rdamn +SMLABT .... 0001 0000 .... .... .... 1100 .... @rdamn +SMLATB .... 0001 0000 .... .... .... 1010 .... @rdamn +SMLATT .... 0001 0000 .... .... .... 1110 .... @rdamn +SMLAWB .... 0001 0010 .... .... .... 1000 .... @rdamn +SMULWB .... 0001 0010 .... 0000 .... 1010 .... @rd0mn +SMLAWT .... 0001 0010 .... .... .... 1100 .... @rdamn +SMULWT .... 0001 0010 .... 0000 .... 1110 .... @rd0mn +SMLALBB .... 0001 0100 .... .... .... 1000 .... @rdamn +SMLALBT .... 0001 0100 .... .... .... 1100 .... @rdamn +SMLALTB .... 0001 0100 .... .... .... 1010 .... @rdamn +SMLALTT .... 0001 0100 .... .... .... 1110 .... @rdamn +SMULBB .... 0001 0110 .... 0000 .... 1000 .... @rd0mn +SMULBT .... 0001 0110 .... 0000 .... 1100 .... @rd0mn +SMULTB .... 0001 0110 .... 0000 .... 1010 .... @rd0mn +SMULTT .... 0001 0110 .... 0000 .... 1110 .... @rd0mn + +# MSR (immediate) and hints + +&msr_i r mask rot imm +@msr_i ---- .... .... mask:4 .... rot:4 imm:8 &msr_i + +{ + { + YIELD ---- 0011 0010 0000 1111 ---- 0000 0001 + WFE ---- 0011 0010 0000 1111 ---- 0000 0010 + WFI ---- 0011 0010 0000 1111 ---- 0000 0011 + + # TODO: Implement SEV, SEVL; may help SMP performance. + # SEV ---- 0011 0010 0000 1111 ---- 0000 0100 + # SEVL ---- 0011 0010 0000 1111 ---- 0000 0101 + + # The canonical nop ends in 00000000, but the whole of the + # rest of the space executes as nop if otherwise unsupported. + NOP ---- 0011 0010 0000 1111 ---- ---- ---- + } + # Note mask = 0 is covered by NOP + MSR_imm .... 0011 0010 .... 1111 .... .... .... @msr_i r=0 +} +MSR_imm .... 0011 0110 .... 1111 .... .... .... @msr_i r=1 + +# Cyclic Redundancy Check + +CRC32B .... 0001 0000 .... .... 0000 0100 .... @rndm +CRC32H .... 0001 0010 .... .... 0000 0100 .... @rndm +CRC32W .... 0001 0100 .... .... 0000 0100 .... @rndm +CRC32CB .... 0001 0000 .... .... 0010 0100 .... @rndm +CRC32CH .... 0001 0010 .... .... 0010 0100 .... @rndm +CRC32CW .... 0001 0100 .... .... 0010 0100 .... @rndm + +# Miscellaneous instructions + +%sysm 8:1 16:4 +%imm16_8_0 8:12 0:4 + +@rm ---- .... .... .... .... .... .... rm:4 &r +@rdm ---- .... .... .... rd:4 .... .... rm:4 &rr +@i16 ---- .... .... .... .... .... .... .... &i imm=%imm16_8_0 + +MRS_bank ---- 0001 0 r:1 00 .... rd:4 001. 0000 0000 &mrs_bank %sysm +MSR_bank ---- 0001 0 r:1 10 .... 1111 001. 0000 rn:4 &msr_bank %sysm + +MRS_reg ---- 0001 0 r:1 00 1111 rd:4 0000 0000 0000 &mrs_reg +MSR_reg ---- 0001 0 r:1 10 mask:4 1111 0000 0000 rn:4 &msr_reg + +BX .... 0001 0010 1111 1111 1111 0001 .... @rm +BXJ .... 0001 0010 1111 1111 1111 0010 .... @rm +BLX_r .... 0001 0010 1111 1111 1111 0011 .... @rm + +CLZ .... 0001 0110 1111 .... 1111 0001 .... @rdm + +ERET ---- 0001 0110 0000 0000 0000 0110 1110 + +HLT .... 0001 0000 .... .... .... 0111 .... @i16 +BKPT .... 0001 0010 .... .... .... 0111 .... @i16 +HVC .... 0001 0100 .... .... .... 0111 .... @i16 +SMC ---- 0001 0110 0000 0000 0000 0111 imm:4 &i + +# Load/Store Dual, Half, Signed Byte (register) + +@ldst_rr_p1w ---- ...1 u:1 . w:1 . rn:4 rt:4 .... .... rm:4 \ + &ldst_rr p=1 shimm=0 shtype=0 +@ldst_rr_pw0 ---- ...0 u:1 . 0 . rn:4 rt:4 .... .... rm:4 \ + &ldst_rr p=0 w=0 shimm=0 shtype=0 + +STRH_rr .... 000. .0.0 .... .... 0000 1011 .... @ldst_rr_pw0 +STRH_rr .... 000. .0.0 .... .... 0000 1011 .... @ldst_rr_p1w + +LDRD_rr .... 000. .0.0 .... .... 0000 1101 .... @ldst_rr_pw0 +LDRD_rr .... 000. .0.0 .... .... 0000 1101 .... @ldst_rr_p1w + +STRD_rr .... 000. .0.0 .... .... 0000 1111 .... @ldst_rr_pw0 +STRD_rr .... 000. .0.0 .... .... 0000 1111 .... @ldst_rr_p1w + +LDRH_rr .... 000. .0.1 .... .... 0000 1011 .... @ldst_rr_pw0 +LDRH_rr .... 000. .0.1 .... .... 0000 1011 .... @ldst_rr_p1w + +LDRSB_rr .... 000. .0.1 .... .... 0000 1101 .... @ldst_rr_pw0 +LDRSB_rr .... 000. .0.1 .... .... 0000 1101 .... @ldst_rr_p1w + +LDRSH_rr .... 000. .0.1 .... .... 0000 1111 .... @ldst_rr_pw0 +LDRSH_rr .... 000. .0.1 .... .... 0000 1111 .... @ldst_rr_p1w + +# Note the unpriv load/stores use the previously invalid P=0, W=1 encoding, +# and act as normal post-indexed (P=0, W=0). +@ldst_rr_p0w1 ---- ...0 u:1 . 1 . rn:4 rt:4 .... .... rm:4 \ + &ldst_rr p=0 w=0 shimm=0 shtype=0 + +STRHT_rr .... 000. .0.0 .... .... 0000 1011 .... @ldst_rr_p0w1 +LDRHT_rr .... 000. .0.1 .... .... 0000 1011 .... @ldst_rr_p0w1 +LDRSBT_rr .... 000. .0.1 .... .... 0000 1101 .... @ldst_rr_p0w1 +LDRSHT_rr .... 000. .0.1 .... .... 0000 1111 .... @ldst_rr_p0w1 + +# Load/Store word and unsigned byte (register) + +@ldst_rs_p1w ---- ...1 u:1 . w:1 . rn:4 rt:4 shimm:5 shtype:2 . rm:4 \ + &ldst_rr p=1 +@ldst_rs_pw0 ---- ...0 u:1 . 0 . rn:4 rt:4 shimm:5 shtype:2 . rm:4 \ + &ldst_rr p=0 w=0 + +STR_rr .... 011. .0.0 .... .... .... ...0 .... @ldst_rs_pw0 +STR_rr .... 011. .0.0 .... .... .... ...0 .... @ldst_rs_p1w +STRB_rr .... 011. .1.0 .... .... .... ...0 .... @ldst_rs_pw0 +STRB_rr .... 011. .1.0 .... .... .... ...0 .... @ldst_rs_p1w + +LDR_rr .... 011. .0.1 .... .... .... ...0 .... @ldst_rs_pw0 +LDR_rr .... 011. .0.1 .... .... .... ...0 .... @ldst_rs_p1w +LDRB_rr .... 011. .1.1 .... .... .... ...0 .... @ldst_rs_pw0 +LDRB_rr .... 011. .1.1 .... .... .... ...0 .... @ldst_rs_p1w + +@ldst_rs_p0w1 ---- ...0 u:1 . 1 . rn:4 rt:4 shimm:5 shtype:2 . rm:4 \ + &ldst_rr p=0 w=0 + +STRT_rr .... 011. .0.0 .... .... .... ...0 .... @ldst_rs_p0w1 +STRBT_rr .... 011. .1.0 .... .... .... ...0 .... @ldst_rs_p0w1 +LDRT_rr .... 011. .0.1 .... .... .... ...0 .... @ldst_rs_p0w1 +LDRBT_rr .... 011. .1.1 .... .... .... ...0 .... @ldst_rs_p0w1 + +# Load/Store Dual, Half, Signed Byte (immediate) + +%imm8s_8_0 8:4 0:4 +@ldst_ri8_p1w ---- ...1 u:1 . w:1 . rn:4 rt:4 .... .... .... \ + &ldst_ri imm=%imm8s_8_0 p=1 +@ldst_ri8_pw0 ---- ...0 u:1 . 0 . rn:4 rt:4 .... .... .... \ + &ldst_ri imm=%imm8s_8_0 p=0 w=0 + +STRH_ri .... 000. .1.0 .... .... .... 1011 .... @ldst_ri8_pw0 +STRH_ri .... 000. .1.0 .... .... .... 1011 .... @ldst_ri8_p1w + +LDRD_ri_a32 .... 000. .1.0 .... .... .... 1101 .... @ldst_ri8_pw0 +LDRD_ri_a32 .... 000. .1.0 .... .... .... 1101 .... @ldst_ri8_p1w + +STRD_ri_a32 .... 000. .1.0 .... .... .... 1111 .... @ldst_ri8_pw0 +STRD_ri_a32 .... 000. .1.0 .... .... .... 1111 .... @ldst_ri8_p1w + +LDRH_ri .... 000. .1.1 .... .... .... 1011 .... @ldst_ri8_pw0 +LDRH_ri .... 000. .1.1 .... .... .... 1011 .... @ldst_ri8_p1w + +LDRSB_ri .... 000. .1.1 .... .... .... 1101 .... @ldst_ri8_pw0 +LDRSB_ri .... 000. .1.1 .... .... .... 1101 .... @ldst_ri8_p1w + +LDRSH_ri .... 000. .1.1 .... .... .... 1111 .... @ldst_ri8_pw0 +LDRSH_ri .... 000. .1.1 .... .... .... 1111 .... @ldst_ri8_p1w + +# Note the unpriv load/stores use the previously invalid P=0, W=1 encoding, +# and act as normal post-indexed (P=0, W=0). +@ldst_ri8_p0w1 ---- ...0 u:1 . 1 . rn:4 rt:4 .... .... .... \ + &ldst_ri imm=%imm8s_8_0 p=0 w=0 + +STRHT_ri .... 000. .1.0 .... .... .... 1011 .... @ldst_ri8_p0w1 +LDRHT_ri .... 000. .1.1 .... .... .... 1011 .... @ldst_ri8_p0w1 +LDRSBT_ri .... 000. .1.1 .... .... .... 1101 .... @ldst_ri8_p0w1 +LDRSHT_ri .... 000. .1.1 .... .... .... 1111 .... @ldst_ri8_p0w1 + +# Load/Store word and unsigned byte (immediate) + +@ldst_ri12_p1w ---- ...1 u:1 . w:1 . rn:4 rt:4 imm:12 &ldst_ri p=1 +@ldst_ri12_pw0 ---- ...0 u:1 . 0 . rn:4 rt:4 imm:12 &ldst_ri p=0 w=0 + +STR_ri .... 010. .0.0 .... .... ............ @ldst_ri12_p1w +STR_ri .... 010. .0.0 .... .... ............ @ldst_ri12_pw0 +STRB_ri .... 010. .1.0 .... .... ............ @ldst_ri12_p1w +STRB_ri .... 010. .1.0 .... .... ............ @ldst_ri12_pw0 + +LDR_ri .... 010. .0.1 .... .... ............ @ldst_ri12_p1w +LDR_ri .... 010. .0.1 .... .... ............ @ldst_ri12_pw0 +LDRB_ri .... 010. .1.1 .... .... ............ @ldst_ri12_p1w +LDRB_ri .... 010. .1.1 .... .... ............ @ldst_ri12_pw0 + +@ldst_ri12_p0w1 ---- ...0 u:1 . 1 . rn:4 rt:4 imm:12 &ldst_ri p=0 w=0 + +STRT_ri .... 010. .0.0 .... .... ............ @ldst_ri12_p0w1 +STRBT_ri .... 010. .1.0 .... .... ............ @ldst_ri12_p0w1 +LDRT_ri .... 010. .0.1 .... .... ............ @ldst_ri12_p0w1 +LDRBT_ri .... 010. .1.1 .... .... ............ @ldst_ri12_p0w1 + +# Synchronization primitives + +@swp ---- .... .... rn:4 rt:4 .... .... rt2:4 + +SWP .... 0001 0000 .... .... 0000 1001 .... @swp +SWPB .... 0001 0100 .... .... 0000 1001 .... @swp + +# Load/Store Exclusive and Load-Acquire/Store-Release +# +# Note rt2 for STREXD/LDREXD is set by the helper after checking rt is even. + +@strex ---- .... .... rn:4 rd:4 .... .... rt:4 \ + &strex imm=0 rt2=15 +@ldrex ---- .... .... rn:4 rt:4 .... .... .... \ + &ldrex imm=0 rt2=15 +@stl ---- .... .... rn:4 .... .... .... rt:4 \ + &ldrex imm=0 rt2=15 + +STREX .... 0001 1000 .... .... 1111 1001 .... @strex +STREXD_a32 .... 0001 1010 .... .... 1111 1001 .... @strex +STREXB .... 0001 1100 .... .... 1111 1001 .... @strex +STREXH .... 0001 1110 .... .... 1111 1001 .... @strex + +STLEX .... 0001 1000 .... .... 1110 1001 .... @strex +STLEXD_a32 .... 0001 1010 .... .... 1110 1001 .... @strex +STLEXB .... 0001 1100 .... .... 1110 1001 .... @strex +STLEXH .... 0001 1110 .... .... 1110 1001 .... @strex + +STL .... 0001 1000 .... 1111 1100 1001 .... @stl +STLB .... 0001 1100 .... 1111 1100 1001 .... @stl +STLH .... 0001 1110 .... 1111 1100 1001 .... @stl + +LDREX .... 0001 1001 .... .... 1111 1001 1111 @ldrex +LDREXD_a32 .... 0001 1011 .... .... 1111 1001 1111 @ldrex +LDREXB .... 0001 1101 .... .... 1111 1001 1111 @ldrex +LDREXH .... 0001 1111 .... .... 1111 1001 1111 @ldrex + +LDAEX .... 0001 1001 .... .... 1110 1001 1111 @ldrex +LDAEXD_a32 .... 0001 1011 .... .... 1110 1001 1111 @ldrex +LDAEXB .... 0001 1101 .... .... 1110 1001 1111 @ldrex +LDAEXH .... 0001 1111 .... .... 1110 1001 1111 @ldrex + +LDA .... 0001 1001 .... .... 1100 1001 1111 @ldrex +LDAB .... 0001 1101 .... .... 1100 1001 1111 @ldrex +LDAH .... 0001 1111 .... .... 1100 1001 1111 @ldrex + +# Media instructions + +# usad8 is usada8 w/ ra=15 +USADA8 ---- 0111 1000 rd:4 ra:4 rm:4 0001 rn:4 + +# ubfx and sbfx +@bfx ---- .... ... widthm1:5 rd:4 lsb:5 ... rn:4 &bfx + +SBFX .... 0111 101 ..... .... ..... 101 .... @bfx +UBFX .... 0111 111 ..... .... ..... 101 .... @bfx + +# bfc is bfi w/ rn=15 +BFCI ---- 0111 110 msb:5 rd:4 lsb:5 001 rn:4 &bfi + +# While we could get UDEF by not including this, add the pattern for +# documentation and to conflict with any other typos in this file. +UDF 1110 0111 1111 ---- ---- ---- 1111 ---- + +# Parallel addition and subtraction + +SADD16 .... 0110 0001 .... .... 1111 0001 .... @rndm +SASX .... 0110 0001 .... .... 1111 0011 .... @rndm +SSAX .... 0110 0001 .... .... 1111 0101 .... @rndm +SSUB16 .... 0110 0001 .... .... 1111 0111 .... @rndm +SADD8 .... 0110 0001 .... .... 1111 1001 .... @rndm +SSUB8 .... 0110 0001 .... .... 1111 1111 .... @rndm + +QADD16 .... 0110 0010 .... .... 1111 0001 .... @rndm +QASX .... 0110 0010 .... .... 1111 0011 .... @rndm +QSAX .... 0110 0010 .... .... 1111 0101 .... @rndm +QSUB16 .... 0110 0010 .... .... 1111 0111 .... @rndm +QADD8 .... 0110 0010 .... .... 1111 1001 .... @rndm +QSUB8 .... 0110 0010 .... .... 1111 1111 .... @rndm + +SHADD16 .... 0110 0011 .... .... 1111 0001 .... @rndm +SHASX .... 0110 0011 .... .... 1111 0011 .... @rndm +SHSAX .... 0110 0011 .... .... 1111 0101 .... @rndm +SHSUB16 .... 0110 0011 .... .... 1111 0111 .... @rndm +SHADD8 .... 0110 0011 .... .... 1111 1001 .... @rndm +SHSUB8 .... 0110 0011 .... .... 1111 1111 .... @rndm + +UADD16 .... 0110 0101 .... .... 1111 0001 .... @rndm +UASX .... 0110 0101 .... .... 1111 0011 .... @rndm +USAX .... 0110 0101 .... .... 1111 0101 .... @rndm +USUB16 .... 0110 0101 .... .... 1111 0111 .... @rndm +UADD8 .... 0110 0101 .... .... 1111 1001 .... @rndm +USUB8 .... 0110 0101 .... .... 1111 1111 .... @rndm + +UQADD16 .... 0110 0110 .... .... 1111 0001 .... @rndm +UQASX .... 0110 0110 .... .... 1111 0011 .... @rndm +UQSAX .... 0110 0110 .... .... 1111 0101 .... @rndm +UQSUB16 .... 0110 0110 .... .... 1111 0111 .... @rndm +UQADD8 .... 0110 0110 .... .... 1111 1001 .... @rndm +UQSUB8 .... 0110 0110 .... .... 1111 1111 .... @rndm + +UHADD16 .... 0110 0111 .... .... 1111 0001 .... @rndm +UHASX .... 0110 0111 .... .... 1111 0011 .... @rndm +UHSAX .... 0110 0111 .... .... 1111 0101 .... @rndm +UHSUB16 .... 0110 0111 .... .... 1111 0111 .... @rndm +UHADD8 .... 0110 0111 .... .... 1111 1001 .... @rndm +UHSUB8 .... 0110 0111 .... .... 1111 1111 .... @rndm + +# Packing, unpacking, saturation, and reversal + +PKH ---- 0110 1000 rn:4 rd:4 imm:5 tb:1 01 rm:4 &pkh + +@sat ---- .... ... satimm:5 rd:4 imm:5 sh:1 .. rn:4 &sat +@sat16 ---- .... .... satimm:4 rd:4 .... .... rn:4 \ + &sat imm=0 sh=0 + +SSAT .... 0110 101. .... .... .... ..01 .... @sat +USAT .... 0110 111. .... .... .... ..01 .... @sat + +SSAT16 .... 0110 1010 .... .... 1111 0011 .... @sat16 +USAT16 .... 0110 1110 .... .... 1111 0011 .... @sat16 + +@rrr_rot ---- .... .... rn:4 rd:4 rot:2 ...... rm:4 &rrr_rot + +SXTAB16 .... 0110 1000 .... .... ..00 0111 .... @rrr_rot +SXTAB .... 0110 1010 .... .... ..00 0111 .... @rrr_rot +SXTAH .... 0110 1011 .... .... ..00 0111 .... @rrr_rot +UXTAB16 .... 0110 1100 .... .... ..00 0111 .... @rrr_rot +UXTAB .... 0110 1110 .... .... ..00 0111 .... @rrr_rot +UXTAH .... 0110 1111 .... .... ..00 0111 .... @rrr_rot + +SEL .... 0110 1000 .... .... 1111 1011 .... @rndm +REV .... 0110 1011 1111 .... 1111 0011 .... @rdm +REV16 .... 0110 1011 1111 .... 1111 1011 .... @rdm +REVSH .... 0110 1111 1111 .... 1111 1011 .... @rdm +RBIT .... 0110 1111 1111 .... 1111 0011 .... @rdm + +# Signed multiply, signed and unsigned divide + +@rdmn ---- .... .... rd:4 .... rm:4 .... rn:4 &rrr + +SMLAD .... 0111 0000 .... .... .... 0001 .... @rdamn +SMLADX .... 0111 0000 .... .... .... 0011 .... @rdamn +SMLSD .... 0111 0000 .... .... .... 0101 .... @rdamn +SMLSDX .... 0111 0000 .... .... .... 0111 .... @rdamn + +SDIV .... 0111 0001 .... 1111 .... 0001 .... @rdmn +UDIV .... 0111 0011 .... 1111 .... 0001 .... @rdmn + +SMLALD .... 0111 0100 .... .... .... 0001 .... @rdamn +SMLALDX .... 0111 0100 .... .... .... 0011 .... @rdamn +SMLSLD .... 0111 0100 .... .... .... 0101 .... @rdamn +SMLSLDX .... 0111 0100 .... .... .... 0111 .... @rdamn + +SMMLA .... 0111 0101 .... .... .... 0001 .... @rdamn +SMMLAR .... 0111 0101 .... .... .... 0011 .... @rdamn +SMMLS .... 0111 0101 .... .... .... 1101 .... @rdamn +SMMLSR .... 0111 0101 .... .... .... 1111 .... @rdamn + +# Block data transfer + +STM ---- 100 b:1 i:1 u:1 w:1 0 rn:4 list:16 &ldst_block +LDM_a32 ---- 100 b:1 i:1 u:1 w:1 1 rn:4 list:16 &ldst_block + +# Branch, branch with link + +%imm26 0:s24 !function=times_4 +@branch ---- .... ........................ &i imm=%imm26 + +B .... 1010 ........................ @branch +BL .... 1011 ........................ @branch + +# Supervisor call + +SVC ---- 1111 imm:24 &i diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 0981303170..297ad5e47a 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2212,6 +2212,9 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) * IO indicates that this register does I/O and therefore its accesses * need to be surrounded by gen_io_start()/gen_io_end(). In particular, * registers which implement clocks or timers require this. + * RAISES_EXC is for when the read or write hook might raise an exception; + * the generated code will synchronize the CPU state before calling the hook + * so that it is safe for the hook to call raise_exception(). */ #define ARM_CP_SPECIAL 0x0001 #define ARM_CP_CONST 0x0002 @@ -2230,10 +2233,11 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) #define ARM_CP_FPU 0x1000 #define ARM_CP_SVE 0x2000 #define ARM_CP_NO_GDB 0x4000 +#define ARM_CP_RAISES_EXC 0x8000 /* Used only as a terminator for ARMCPRegInfo lists */ #define ARM_CP_SENTINEL 0xffff /* Mask of only the flag bits in a type field */ -#define ARM_CP_FLAG_MASK 0x70ff +#define ARM_CP_FLAG_MASK 0xf0ff /* Valid values for ARMCPRegInfo state field, indicating which of * the AArch32 and AArch64 execution states this register is visible in. diff --git a/target/arm/helper.c b/target/arm/helper.c index 7e0d5398ab..507026c915 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2946,6 +2946,73 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs, &prot, &page_size, &fi, &cacheattrs); + if (ret) { + /* + * Some kinds of translation fault must cause exceptions rather + * than being reported in the PAR. + */ + int current_el = arm_current_el(env); + int target_el; + uint32_t syn, fsr, fsc; + bool take_exc = false; + + if (fi.s1ptw && current_el == 1 && !arm_is_secure(env) + && (mmu_idx == ARMMMUIdx_S1NSE1 || mmu_idx == ARMMMUIdx_S1NSE0)) { + /* + * Synchronous stage 2 fault on an access made as part of the + * translation table walk for AT S1E0* or AT S1E1* insn + * executed from NS EL1. If this is a synchronous external abort + * and SCR_EL3.EA == 1, then we take a synchronous external abort + * to EL3. Otherwise the fault is taken as an exception to EL2, + * and HPFAR_EL2 holds the faulting IPA. + */ + if (fi.type == ARMFault_SyncExternalOnWalk && + (env->cp15.scr_el3 & SCR_EA)) { + target_el = 3; + } else { + env->cp15.hpfar_el2 = extract64(fi.s2addr, 12, 47) << 4; + target_el = 2; + } + take_exc = true; + } else if (fi.type == ARMFault_SyncExternalOnWalk) { + /* + * Synchronous external aborts during a translation table walk + * are taken as Data Abort exceptions. + */ + if (fi.stage2) { + if (current_el == 3) { + target_el = 3; + } else { + target_el = 2; + } + } else { + target_el = exception_target_el(env); + } + take_exc = true; + } + + if (take_exc) { + /* Construct FSR and FSC using same logic as arm_deliver_fault() */ + if (target_el == 2 || arm_el_is_aa64(env, target_el) || + arm_s1_regime_using_lpae_format(env, mmu_idx)) { + fsr = arm_fi_to_lfsc(&fi); + fsc = extract32(fsr, 0, 6); + } else { + fsr = arm_fi_to_sfsc(&fi); + fsc = 0x3f; + } + /* + * Report exception with ESR indicating a fault due to a + * translation table walk for a cache maintenance instruction. + */ + syn = syn_data_abort_no_iss(current_el == target_el, + fi.ea, 1, fi.s1ptw, 1, fsc); + env->exception.vaddress = value; + env->exception.fsr = fsr; + raise_exception(env, EXCP_DATA_ABORT, syn, target_el); + } + } + if (is_a64(env)) { format64 = true; } else if (arm_feature(env, ARM_FEATURE_LPAE)) { @@ -3150,7 +3217,7 @@ static const ARMCPRegInfo vapa_cp_reginfo[] = { /* This underdecoding is safe because the reginfo is NO_RAW. */ { .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY, .access = PL1_W, .accessfn = ats_access, - .writefn = ats_write, .type = ARM_CP_NO_RAW }, + .writefn = ats_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC }, #endif REGINFO_SENTINEL }; @@ -4283,35 +4350,45 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { /* 64 bit address translation operations */ { .name = "AT_S1E1R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 0, - .access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn = ats_write64 }, { .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 1, - .access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn = ats_write64 }, { .name = "AT_S1E0R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 2, - .access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn = ats_write64 }, { .name = "AT_S1E0W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3, - .access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn = ats_write64 }, { .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4, - .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn = ats_write64 }, { .name = "AT_S12E1W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 5, - .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn = ats_write64 }, { .name = "AT_S12E0R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 6, - .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn = ats_write64 }, { .name = "AT_S12E0W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 7, - .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn = ats_write64 }, /* AT S1E2* are elsewhere as they UNDEF from EL3 if EL2 is not present */ { .name = "AT_S1E3R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 0, - .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .access = PL3_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn = ats_write64 }, { .name = "AT_S1E3W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 1, - .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .access = PL3_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn = ats_write64 }, { .name = "PAR_EL1", .state = ARM_CP_STATE_AA64, .type = ARM_CP_ALIAS, .opc0 = 3, .opc1 = 0, .crn = 7, .crm = 4, .opc2 = 0, @@ -4893,11 +4970,11 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { { .name = "AT_S1E2R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0, .access = PL2_W, .accessfn = at_s1e2_access, - .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, { .name = "AT_S1E2W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1, .access = PL2_W, .accessfn = at_s1e2_access, - .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, /* The AArch32 ATS1H* operations are CONSTRAINED UNPREDICTABLE * if EL2 is not implemented; we choose to UNDEF. Behaviour at EL3 * with SCR.NS == 0 outside Monitor mode is UNPREDICTABLE; we choose @@ -4905,10 +4982,10 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { */ { .name = "ATS1HR", .cp = 15, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0, .access = PL2_W, - .writefn = ats1h_write, .type = ARM_CP_NO_RAW }, + .writefn = ats1h_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC }, { .name = "ATS1HW", .cp = 15, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1, .access = PL2_W, - .writefn = ats1h_write, .type = ARM_CP_NO_RAW }, + .writefn = ats1h_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC }, { .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0, /* ARMv7 requires bit 0 and 1 to reset to 1. ARMv8 defines the diff --git a/target/arm/t16.decode b/target/arm/t16.decode new file mode 100644 index 0000000000..43b9a267a1 --- /dev/null +++ b/target/arm/t16.decode @@ -0,0 +1,281 @@ +# Thumb1 instructions +# +# Copyright (c) 2019 Linaro, Ltd +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. + +# +# This file is processed by scripts/decodetree.py +# + +&empty !extern +&s_rrr_shi !extern s rd rn rm shim shty +&s_rrr_shr !extern s rn rd rm rs shty +&s_rri_rot !extern s rn rd imm rot +&s_rrrr !extern s rd rn rm ra +&rrr_rot !extern rd rn rm rot +&rr !extern rd rm +&ri !extern rd imm +&r !extern rm +&i !extern imm +&ldst_rr !extern p w u rn rt rm shimm shtype +&ldst_ri !extern p w u rn rt imm +&ldst_block !extern rn i b u w list +&setend !extern E +&cps !extern mode imod M A I F +&ci !extern cond imm + +# Set S if the instruction is outside of an IT block. +%s !function=t16_setflags + +# Data-processing (two low registers) + +%reg_0 0:3 + +@lll_noshr ...... .... rm:3 rd:3 \ + &s_rrr_shi %s rn=%reg_0 shim=0 shty=0 +@xll_noshr ...... .... rm:3 rn:3 \ + &s_rrr_shi s=1 rd=0 shim=0 shty=0 +@lxl_shr ...... .... rs:3 rd:3 \ + &s_rrr_shr %s rm=%reg_0 rn=0 + +AND_rrri 010000 0000 ... ... @lll_noshr +EOR_rrri 010000 0001 ... ... @lll_noshr +MOV_rxrr 010000 0010 ... ... @lxl_shr shty=0 # LSL +MOV_rxrr 010000 0011 ... ... @lxl_shr shty=1 # LSR +MOV_rxrr 010000 0100 ... ... @lxl_shr shty=2 # ASR +ADC_rrri 010000 0101 ... ... @lll_noshr +SBC_rrri 010000 0110 ... ... @lll_noshr +MOV_rxrr 010000 0111 ... ... @lxl_shr shty=3 # ROR +TST_xrri 010000 1000 ... ... @xll_noshr +RSB_rri 010000 1001 rn:3 rd:3 &s_rri_rot %s imm=0 rot=0 +CMP_xrri 010000 1010 ... ... @xll_noshr +CMN_xrri 010000 1011 ... ... @xll_noshr +ORR_rrri 010000 1100 ... ... @lll_noshr +MUL 010000 1101 rn:3 rd:3 &s_rrrr %s rm=%reg_0 ra=0 +BIC_rrri 010000 1110 ... ... @lll_noshr +MVN_rxri 010000 1111 ... ... @lll_noshr + +# Load/store (register offset) + +@ldst_rr ....... rm:3 rn:3 rt:3 \ + &ldst_rr p=1 w=0 u=1 shimm=0 shtype=0 + +STR_rr 0101 000 ... ... ... @ldst_rr +STRH_rr 0101 001 ... ... ... @ldst_rr +STRB_rr 0101 010 ... ... ... @ldst_rr +LDRSB_rr 0101 011 ... ... ... @ldst_rr +LDR_rr 0101 100 ... ... ... @ldst_rr +LDRH_rr 0101 101 ... ... ... @ldst_rr +LDRB_rr 0101 110 ... ... ... @ldst_rr +LDRSH_rr 0101 111 ... ... ... @ldst_rr + +# Load/store word/byte (immediate offset) + +%imm5_6x4 6:5 !function=times_4 + +@ldst_ri_1 ..... imm:5 rn:3 rt:3 \ + &ldst_ri p=1 w=0 u=1 +@ldst_ri_4 ..... ..... rn:3 rt:3 \ + &ldst_ri p=1 w=0 u=1 imm=%imm5_6x4 + +STR_ri 01100 ..... ... ... @ldst_ri_4 +LDR_ri 01101 ..... ... ... @ldst_ri_4 +STRB_ri 01110 ..... ... ... @ldst_ri_1 +LDRB_ri 01111 ..... ... ... @ldst_ri_1 + +# Load/store halfword (immediate offset) + +%imm5_6x2 6:5 !function=times_2 +@ldst_ri_2 ..... ..... rn:3 rt:3 \ + &ldst_ri p=1 w=0 u=1 imm=%imm5_6x2 + +STRH_ri 10000 ..... ... ... @ldst_ri_2 +LDRH_ri 10001 ..... ... ... @ldst_ri_2 + +# Load/store (SP-relative) + +%imm8_0x4 0:8 !function=times_4 +@ldst_spec_i ..... rt:3 ........ \ + &ldst_ri p=1 w=0 u=1 imm=%imm8_0x4 + +STR_ri 10010 ... ........ @ldst_spec_i rn=13 +LDR_ri 10011 ... ........ @ldst_spec_i rn=13 + +# Load (PC-relative) + +LDR_ri 01001 ... ........ @ldst_spec_i rn=15 + +# Add PC/SP (immediate) + +ADR 10100 rd:3 ........ imm=%imm8_0x4 +ADD_rri 10101 rd:3 ........ \ + &s_rri_rot rn=13 s=0 rot=0 imm=%imm8_0x4 # SP + +# Load/store multiple + +@ldstm ..... rn:3 list:8 &ldst_block i=1 b=0 u=0 w=1 + +STM 11000 ... ........ @ldstm +LDM_t16 11001 ... ........ @ldstm + +# Shift (immediate) + +@shift_i ..... shim:5 rm:3 rd:3 &s_rrr_shi %s rn=%reg_0 + +MOV_rxri 000 00 ..... ... ... @shift_i shty=0 # LSL +MOV_rxri 000 01 ..... ... ... @shift_i shty=1 # LSR +MOV_rxri 000 10 ..... ... ... @shift_i shty=2 # ASR + +# Add/subtract (three low registers) + +@addsub_3 ....... rm:3 rn:3 rd:3 \ + &s_rrr_shi %s shim=0 shty=0 + +ADD_rrri 0001100 ... ... ... @addsub_3 +SUB_rrri 0001101 ... ... ... @addsub_3 + +# Add/subtract (two low registers and immediate) + +@addsub_2i ....... imm:3 rn:3 rd:3 \ + &s_rri_rot %s rot=0 + +ADD_rri 0001 110 ... ... ... @addsub_2i +SUB_rri 0001 111 ... ... ... @addsub_2i + +# Add, subtract, compare, move (one low register and immediate) + +%reg_8 8:3 +@arith_1i ..... rd:3 imm:8 \ + &s_rri_rot rot=0 rn=%reg_8 + +MOV_rxi 00100 ... ........ @arith_1i %s +CMP_xri 00101 ... ........ @arith_1i s=1 +ADD_rri 00110 ... ........ @arith_1i %s +SUB_rri 00111 ... ........ @arith_1i %s + +# Add, compare, move (two high registers) + +%reg_0_7 7:1 0:3 +@addsub_2h .... .... . rm:4 ... \ + &s_rrr_shi rd=%reg_0_7 rn=%reg_0_7 shim=0 shty=0 + +ADD_rrri 0100 0100 . .... ... @addsub_2h s=0 +CMP_xrri 0100 0101 . .... ... @addsub_2h s=1 +MOV_rxri 0100 0110 . .... ... @addsub_2h s=0 + +# Adjust SP (immediate) + +%imm7_0x4 0:7 !function=times_4 +@addsub_sp_i .... .... . ....... \ + &s_rri_rot s=0 rd=13 rn=13 rot=0 imm=%imm7_0x4 + +ADD_rri 1011 0000 0 ....... @addsub_sp_i +SUB_rri 1011 0000 1 ....... @addsub_sp_i + +# Branch and exchange + +@branchr .... .... . rm:4 ... &r + +BX 0100 0111 0 .... 000 @branchr +BLX_r 0100 0111 1 .... 000 @branchr +BXNS 0100 0111 0 .... 100 @branchr +BLXNS 0100 0111 1 .... 100 @branchr + +# Extend + +@extend .... .... .. rm:3 rd:3 &rrr_rot rn=15 rot=0 + +SXTAH 1011 0010 00 ... ... @extend +SXTAB 1011 0010 01 ... ... @extend +UXTAH 1011 0010 10 ... ... @extend +UXTAB 1011 0010 11 ... ... @extend + +# Change processor state + +%imod 4:1 !function=plus_2 + +SETEND 1011 0110 010 1 E:1 000 &setend +{ + CPS 1011 0110 011 . 0 A:1 I:1 F:1 &cps mode=0 M=0 %imod + CPS_v7m 1011 0110 011 im:1 00 I:1 F:1 +} + +# Reverse bytes + +@rdm .... .... .. rm:3 rd:3 &rr + +REV 1011 1010 00 ... ... @rdm +REV16 1011 1010 01 ... ... @rdm +REVSH 1011 1010 11 ... ... @rdm + +# Hints + +{ + { + YIELD 1011 1111 0001 0000 + WFE 1011 1111 0010 0000 + WFI 1011 1111 0011 0000 + + # TODO: Implement SEV, SEVL; may help SMP performance. + # SEV 1011 1111 0100 0000 + # SEVL 1011 1111 0101 0000 + + # The canonical nop has the second nibble as 0000, but the whole of the + # rest of the space is a reserved hint, behaves as nop. + NOP 1011 1111 ---- 0000 + } + IT 1011 1111 cond_mask:8 +} + +# Miscellaneous 16-bit instructions + +%imm6_9_3 9:1 3:5 !function=times_2 + +HLT 1011 1010 10 imm:6 &i +BKPT 1011 1110 imm:8 &i +CBZ 1011 nz:1 0.1 ..... rn:3 imm=%imm6_9_3 + +# Push and Pop + +%push_list 0:9 !function=t16_push_list +%pop_list 0:9 !function=t16_pop_list + +STM 1011 010 ......... \ + &ldst_block i=0 b=1 u=0 w=1 rn=13 list=%push_list +LDM_t16 1011 110 ......... \ + &ldst_block i=1 b=0 u=0 w=1 rn=13 list=%pop_list + +# Conditional branches, Supervisor call + +%imm8_0x2 0:s8 !function=times_2 + +{ + UDF 1101 1110 ---- ---- + SVC 1101 1111 imm:8 &i + B_cond_thumb 1101 cond:4 ........ &ci imm=%imm8_0x2 +} + +# Unconditional Branch + +%imm11_0x2 0:s11 !function=times_2 + +B 11100 ........... &i imm=%imm11_0x2 + +# thumb_insn_is_16bit() ensures we won't be decoding these as +# T16 instructions for a Thumb2 CPU, so these patterns must be +# a Thumb1 split BL/BLX. +BLX_suffix 11101 imm:11 &i +BL_BLX_prefix 11110 imm:s11 &i +BL_suffix 11111 imm:11 &i diff --git a/target/arm/t32.decode b/target/arm/t32.decode new file mode 100644 index 0000000000..c63082fc9c --- /dev/null +++ b/target/arm/t32.decode @@ -0,0 +1,631 @@ +# Thumb2 instructions +# +# Copyright (c) 2019 Linaro, Ltd +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. + +# +# This file is processed by scripts/decodetree.py +# + +&empty !extern +&s_rrr_shi !extern s rd rn rm shim shty +&s_rrr_shr !extern s rn rd rm rs shty +&s_rri_rot !extern s rn rd imm rot +&s_rrrr !extern s rd rn rm ra +&rrrr !extern rd rn rm ra +&rrr_rot !extern rd rn rm rot +&rrr !extern rd rn rm +&rr !extern rd rm +&ri !extern rd imm +&r !extern rm +&i !extern imm +&msr_reg !extern rn r mask +&mrs_reg !extern rd r +&msr_bank !extern rn r sysm +&mrs_bank !extern rd r sysm +&ldst_rr !extern p w u rn rt rm shimm shtype +&ldst_ri !extern p w u rn rt imm +&ldst_block !extern rn i b u w list +&strex !extern rn rd rt rt2 imm +&ldrex !extern rn rt rt2 imm +&bfx !extern rd rn lsb widthm1 +&bfi !extern rd rn lsb msb +&sat !extern rd rn satimm imm sh +&pkh !extern rd rn rm imm tb +&cps !extern mode imod M A I F + +# Data-processing (register) + +%imm5_12_6 12:3 6:2 + +@s_rrr_shi ....... .... s:1 rn:4 .... rd:4 .. shty:2 rm:4 \ + &s_rrr_shi shim=%imm5_12_6 +@s_rxr_shi ....... .... s:1 .... .... rd:4 .. shty:2 rm:4 \ + &s_rrr_shi shim=%imm5_12_6 rn=0 +@S_xrr_shi ....... .... . rn:4 .... .... .. shty:2 rm:4 \ + &s_rrr_shi shim=%imm5_12_6 s=1 rd=0 + +{ + TST_xrri 1110101 0000 1 .... 0 ... 1111 .... .... @S_xrr_shi + AND_rrri 1110101 0000 . .... 0 ... .... .... .... @s_rrr_shi +} +BIC_rrri 1110101 0001 . .... 0 ... .... .... .... @s_rrr_shi +{ + MOV_rxri 1110101 0010 . 1111 0 ... .... .... .... @s_rxr_shi + ORR_rrri 1110101 0010 . .... 0 ... .... .... .... @s_rrr_shi +} +{ + MVN_rxri 1110101 0011 . 1111 0 ... .... .... .... @s_rxr_shi + ORN_rrri 1110101 0011 . .... 0 ... .... .... .... @s_rrr_shi +} +{ + TEQ_xrri 1110101 0100 1 .... 0 ... 1111 .... .... @S_xrr_shi + EOR_rrri 1110101 0100 . .... 0 ... .... .... .... @s_rrr_shi +} +PKH 1110101 0110 0 rn:4 0 ... rd:4 .. tb:1 0 rm:4 \ + &pkh imm=%imm5_12_6 +{ + CMN_xrri 1110101 1000 1 .... 0 ... 1111 .... .... @S_xrr_shi + ADD_rrri 1110101 1000 . .... 0 ... .... .... .... @s_rrr_shi +} +ADC_rrri 1110101 1010 . .... 0 ... .... .... .... @s_rrr_shi +SBC_rrri 1110101 1011 . .... 0 ... .... .... .... @s_rrr_shi +{ + CMP_xrri 1110101 1101 1 .... 0 ... 1111 .... .... @S_xrr_shi + SUB_rrri 1110101 1101 . .... 0 ... .... .... .... @s_rrr_shi +} +RSB_rrri 1110101 1110 . .... 0 ... .... .... .... @s_rrr_shi + +# Data-processing (register-shifted register) + +MOV_rxrr 1111 1010 0 shty:2 s:1 rm:4 1111 rd:4 0000 rs:4 \ + &s_rrr_shr rn=0 + +# Data-processing (immediate) + +%t32extrot 26:1 12:3 0:8 !function=t32_expandimm_rot +%t32extimm 26:1 12:3 0:8 !function=t32_expandimm_imm + +@s_rri_rot ....... .... s:1 rn:4 . ... rd:4 ........ \ + &s_rri_rot imm=%t32extimm rot=%t32extrot +@s_rxi_rot ....... .... s:1 .... . ... rd:4 ........ \ + &s_rri_rot imm=%t32extimm rot=%t32extrot rn=0 +@S_xri_rot ....... .... . rn:4 . ... .... ........ \ + &s_rri_rot imm=%t32extimm rot=%t32extrot s=1 rd=0 + +{ + TST_xri 1111 0.0 0000 1 .... 0 ... 1111 ........ @S_xri_rot + AND_rri 1111 0.0 0000 . .... 0 ... .... ........ @s_rri_rot +} +BIC_rri 1111 0.0 0001 . .... 0 ... .... ........ @s_rri_rot +{ + MOV_rxi 1111 0.0 0010 . 1111 0 ... .... ........ @s_rxi_rot + ORR_rri 1111 0.0 0010 . .... 0 ... .... ........ @s_rri_rot +} +{ + MVN_rxi 1111 0.0 0011 . 1111 0 ... .... ........ @s_rxi_rot + ORN_rri 1111 0.0 0011 . .... 0 ... .... ........ @s_rri_rot +} +{ + TEQ_xri 1111 0.0 0100 1 .... 0 ... 1111 ........ @S_xri_rot + EOR_rri 1111 0.0 0100 . .... 0 ... .... ........ @s_rri_rot +} +{ + CMN_xri 1111 0.0 1000 1 .... 0 ... 1111 ........ @S_xri_rot + ADD_rri 1111 0.0 1000 . .... 0 ... .... ........ @s_rri_rot +} +ADC_rri 1111 0.0 1010 . .... 0 ... .... ........ @s_rri_rot +SBC_rri 1111 0.0 1011 . .... 0 ... .... ........ @s_rri_rot +{ + CMP_xri 1111 0.0 1101 1 .... 0 ... 1111 ........ @S_xri_rot + SUB_rri 1111 0.0 1101 . .... 0 ... .... ........ @s_rri_rot +} +RSB_rri 1111 0.0 1110 . .... 0 ... .... ........ @s_rri_rot + +# Data processing (plain binary immediate) + +%imm12_26_12_0 26:1 12:3 0:8 +%neg12_26_12_0 26:1 12:3 0:8 !function=negate +@s0_rri_12 .... ... .... . rn:4 . ... rd:4 ........ \ + &s_rri_rot imm=%imm12_26_12_0 rot=0 s=0 + +{ + ADR 1111 0.1 0000 0 1111 0 ... rd:4 ........ \ + &ri imm=%imm12_26_12_0 + ADD_rri 1111 0.1 0000 0 .... 0 ... .... ........ @s0_rri_12 +} +{ + ADR 1111 0.1 0101 0 1111 0 ... rd:4 ........ \ + &ri imm=%neg12_26_12_0 + SUB_rri 1111 0.1 0101 0 .... 0 ... .... ........ @s0_rri_12 +} + +# Move Wide + +%imm16_26_16_12_0 16:4 26:1 12:3 0:8 +@mov16 .... .... .... .... .... rd:4 .... .... \ + &ri imm=%imm16_26_16_12_0 + +MOVW 1111 0.10 0100 .... 0 ... .... ........ @mov16 +MOVT 1111 0.10 1100 .... 0 ... .... ........ @mov16 + +# Saturate, bitfield + +@sat .... .... .. sh:1 . rn:4 . ... rd:4 .. . satimm:5 \ + &sat imm=%imm5_12_6 +@sat16 .... .... .. . . rn:4 . ... rd:4 .. . satimm:5 \ + &sat sh=0 imm=0 + +{ + SSAT16 1111 0011 001 0 .... 0 000 .... 00 0 ..... @sat16 + SSAT 1111 0011 00. 0 .... 0 ... .... .. 0 ..... @sat +} +{ + USAT16 1111 0011 101 0 .... 0 000 .... 00 0 ..... @sat16 + USAT 1111 0011 10. 0 .... 0 ... .... .. 0 ..... @sat +} + +@bfx .... .... ... . rn:4 . ... rd:4 .. . widthm1:5 \ + &bfx lsb=%imm5_12_6 +@bfi .... .... ... . rn:4 . ... rd:4 .. . msb:5 \ + &bfi lsb=%imm5_12_6 + +SBFX 1111 0011 010 0 .... 0 ... .... ..0..... @bfx +UBFX 1111 0011 110 0 .... 0 ... .... ..0..... @bfx + +# bfc is bfi w/ rn=15 +BFCI 1111 0011 011 0 .... 0 ... .... ..0..... @bfi + +# Multiply and multiply accumulate + +@s0_rnadm .... .... .... rn:4 ra:4 rd:4 .... rm:4 &s_rrrr s=0 +@s0_rn0dm .... .... .... rn:4 .... rd:4 .... rm:4 &s_rrrr ra=0 s=0 +@rnadm .... .... .... rn:4 ra:4 rd:4 .... rm:4 &rrrr +@rn0dm .... .... .... rn:4 .... rd:4 .... rm:4 &rrrr ra=0 +@rndm .... .... .... rn:4 .... rd:4 .... rm:4 &rrr +@rdm .... .... .... .... .... rd:4 .... rm:4 &rr + +{ + MUL 1111 1011 0000 .... 1111 .... 0000 .... @s0_rn0dm + MLA 1111 1011 0000 .... .... .... 0000 .... @s0_rnadm +} +MLS 1111 1011 0000 .... .... .... 0001 .... @rnadm +SMULL 1111 1011 1000 .... .... .... 0000 .... @s0_rnadm +UMULL 1111 1011 1010 .... .... .... 0000 .... @s0_rnadm +SMLAL 1111 1011 1100 .... .... .... 0000 .... @s0_rnadm +UMLAL 1111 1011 1110 .... .... .... 0000 .... @s0_rnadm +UMAAL 1111 1011 1110 .... .... .... 0110 .... @rnadm +{ + SMULWB 1111 1011 0011 .... 1111 .... 0000 .... @rn0dm + SMLAWB 1111 1011 0011 .... .... .... 0000 .... @rnadm +} +{ + SMULWT 1111 1011 0011 .... 1111 .... 0001 .... @rn0dm + SMLAWT 1111 1011 0011 .... .... .... 0001 .... @rnadm +} +{ + SMULBB 1111 1011 0001 .... 1111 .... 0000 .... @rn0dm + SMLABB 1111 1011 0001 .... .... .... 0000 .... @rnadm +} +{ + SMULBT 1111 1011 0001 .... 1111 .... 0001 .... @rn0dm + SMLABT 1111 1011 0001 .... .... .... 0001 .... @rnadm +} +{ + SMULTB 1111 1011 0001 .... 1111 .... 0010 .... @rn0dm + SMLATB 1111 1011 0001 .... .... .... 0010 .... @rnadm +} +{ + SMULTT 1111 1011 0001 .... 1111 .... 0011 .... @rn0dm + SMLATT 1111 1011 0001 .... .... .... 0011 .... @rnadm +} +SMLALBB 1111 1011 1100 .... .... .... 1000 .... @rnadm +SMLALBT 1111 1011 1100 .... .... .... 1001 .... @rnadm +SMLALTB 1111 1011 1100 .... .... .... 1010 .... @rnadm +SMLALTT 1111 1011 1100 .... .... .... 1011 .... @rnadm + +# usad8 is usada8 w/ ra=15 +USADA8 1111 1011 0111 .... .... .... 0000 .... @rnadm + +SMLAD 1111 1011 0010 .... .... .... 0000 .... @rnadm +SMLADX 1111 1011 0010 .... .... .... 0001 .... @rnadm +SMLSD 1111 1011 0100 .... .... .... 0000 .... @rnadm +SMLSDX 1111 1011 0100 .... .... .... 0001 .... @rnadm + +SMLALD 1111 1011 1100 .... .... .... 1100 .... @rnadm +SMLALDX 1111 1011 1100 .... .... .... 1101 .... @rnadm +SMLSLD 1111 1011 1101 .... .... .... 1100 .... @rnadm +SMLSLDX 1111 1011 1101 .... .... .... 1101 .... @rnadm + +SMMLA 1111 1011 0101 .... .... .... 0000 .... @rnadm +SMMLAR 1111 1011 0101 .... .... .... 0001 .... @rnadm +SMMLS 1111 1011 0110 .... .... .... 0000 .... @rnadm +SMMLSR 1111 1011 0110 .... .... .... 0001 .... @rnadm + +SDIV 1111 1011 1001 .... 1111 .... 1111 .... @rndm +UDIV 1111 1011 1011 .... 1111 .... 1111 .... @rndm + +# Data-processing (two source registers) + +QADD 1111 1010 1000 .... 1111 .... 1000 .... @rndm +QSUB 1111 1010 1000 .... 1111 .... 1010 .... @rndm +QDADD 1111 1010 1000 .... 1111 .... 1001 .... @rndm +QDSUB 1111 1010 1000 .... 1111 .... 1011 .... @rndm + +CRC32B 1111 1010 1100 .... 1111 .... 1000 .... @rndm +CRC32H 1111 1010 1100 .... 1111 .... 1001 .... @rndm +CRC32W 1111 1010 1100 .... 1111 .... 1010 .... @rndm +CRC32CB 1111 1010 1101 .... 1111 .... 1000 .... @rndm +CRC32CH 1111 1010 1101 .... 1111 .... 1001 .... @rndm +CRC32CW 1111 1010 1101 .... 1111 .... 1010 .... @rndm + +SEL 1111 1010 1010 .... 1111 .... 1000 .... @rndm + +# Note rn != rm is CONSTRAINED UNPREDICTABLE; we choose to ignore rn. +REV 1111 1010 1001 ---- 1111 .... 1000 .... @rdm +REV16 1111 1010 1001 ---- 1111 .... 1001 .... @rdm +RBIT 1111 1010 1001 ---- 1111 .... 1010 .... @rdm +REVSH 1111 1010 1001 ---- 1111 .... 1011 .... @rdm +CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm + +# Branches and miscellaneous control + +%msr_sysm 4:1 8:4 +%mrs_sysm 4:1 16:4 +%imm16_16_0 16:4 0:12 +%imm21 26:s1 11:1 13:1 16:6 0:11 !function=times_2 +&ci cond imm + +{ + # Group insn[25:23] = 111, which is cond=111x for the branch below, + # or unconditional, which would be illegal for the branch. + { + # Hints + { + YIELD 1111 0011 1010 1111 1000 0000 0000 0001 + WFE 1111 0011 1010 1111 1000 0000 0000 0010 + WFI 1111 0011 1010 1111 1000 0000 0000 0011 + + # TODO: Implement SEV, SEVL; may help SMP performance. + # SEV 1111 0011 1010 1111 1000 0000 0000 0100 + # SEVL 1111 0011 1010 1111 1000 0000 0000 0101 + + # The canonical nop ends in 0000 0000, but the whole rest + # of the space is "reserved hint, behaves as nop". + NOP 1111 0011 1010 1111 1000 0000 ---- ---- + } + + # If imod == '00' && M == '0' then SEE "Hint instructions", above. + CPS 1111 0011 1010 1111 1000 0 imod:2 M:1 A:1 I:1 F:1 mode:5 \ + &cps + + # Miscellaneous control + { + CLREX 1111 0011 1011 1111 1000 1111 0010 1111 + DSB 1111 0011 1011 1111 1000 1111 0100 ---- + DMB 1111 0011 1011 1111 1000 1111 0101 ---- + ISB 1111 0011 1011 1111 1000 1111 0110 ---- + SB 1111 0011 1011 1111 1000 1111 0111 0000 + } + + # Note that the v7m insn overlaps both the normal and banked insn. + { + MRS_bank 1111 0011 111 r:1 .... 1000 rd:4 001. 0000 \ + &mrs_bank sysm=%mrs_sysm + MRS_reg 1111 0011 111 r:1 1111 1000 rd:4 0000 0000 &mrs_reg + MRS_v7m 1111 0011 111 0 1111 1000 rd:4 sysm:8 + } + { + MSR_bank 1111 0011 100 r:1 rn:4 1000 .... 001. 0000 \ + &msr_bank sysm=%msr_sysm + MSR_reg 1111 0011 100 r:1 rn:4 1000 mask:4 0000 0000 &msr_reg + MSR_v7m 1111 0011 100 0 rn:4 1000 mask:2 00 sysm:8 + } + BXJ 1111 0011 1100 rm:4 1000 1111 0000 0000 &r + { + # At v6T2, this is the T5 encoding of SUBS PC, LR, #IMM, and works as for + # every other encoding of SUBS. With v7VE, IMM=0 is redefined as ERET. + # The distinction between the two only matters for Hyp mode. + ERET 1111 0011 1101 1110 1000 1111 0000 0000 + SUB_rri 1111 0011 1101 1110 1000 1111 imm:8 \ + &s_rri_rot rot=0 s=1 rd=15 rn=14 + } + SMC 1111 0111 1111 imm:4 1000 0000 0000 0000 &i + HVC 1111 0111 1110 .... 1000 .... .... .... \ + &i imm=%imm16_16_0 + UDF 1111 0111 1111 ---- 1010 ---- ---- ---- + } + B_cond_thumb 1111 0. cond:4 ...... 10.0 ............ &ci imm=%imm21 +} + +# Load/store (register, immediate, literal) + +@ldst_rr .... .... .... rn:4 rt:4 ...... shimm:2 rm:4 \ + &ldst_rr p=1 w=0 u=1 shtype=0 +@ldst_ri_idx .... .... .... rn:4 rt:4 . p:1 u:1 . imm:8 \ + &ldst_ri w=1 +@ldst_ri_neg .... .... .... rn:4 rt:4 .... imm:8 \ + &ldst_ri p=1 w=0 u=0 +@ldst_ri_unp .... .... .... rn:4 rt:4 .... imm:8 \ + &ldst_ri p=1 w=0 u=1 +@ldst_ri_pos .... .... .... rn:4 rt:4 imm:12 \ + &ldst_ri p=1 w=0 u=1 +@ldst_ri_lit .... .... u:1 ... .... rt:4 imm:12 \ + &ldst_ri p=1 w=0 rn=15 + +STRB_rr 1111 1000 0000 .... .... 000000 .. .... @ldst_rr +STRB_ri 1111 1000 0000 .... .... 1..1 ........ @ldst_ri_idx +STRB_ri 1111 1000 0000 .... .... 1100 ........ @ldst_ri_neg +STRBT_ri 1111 1000 0000 .... .... 1110 ........ @ldst_ri_unp +STRB_ri 1111 1000 1000 .... .... ............ @ldst_ri_pos + +STRH_rr 1111 1000 0010 .... .... 000000 .. .... @ldst_rr +STRH_ri 1111 1000 0010 .... .... 1..1 ........ @ldst_ri_idx +STRH_ri 1111 1000 0010 .... .... 1100 ........ @ldst_ri_neg +STRHT_ri 1111 1000 0010 .... .... 1110 ........ @ldst_ri_unp +STRH_ri 1111 1000 1010 .... .... ............ @ldst_ri_pos + +STR_rr 1111 1000 0100 .... .... 000000 .. .... @ldst_rr +STR_ri 1111 1000 0100 .... .... 1..1 ........ @ldst_ri_idx +STR_ri 1111 1000 0100 .... .... 1100 ........ @ldst_ri_neg +STRT_ri 1111 1000 0100 .... .... 1110 ........ @ldst_ri_unp +STR_ri 1111 1000 1100 .... .... ............ @ldst_ri_pos + +# Note that Load, unsigned (literal) overlaps all other load encodings. +{ + { + NOP 1111 1000 -001 1111 1111 ------------ # PLD + LDRB_ri 1111 1000 .001 1111 .... ............ @ldst_ri_lit + } + { + NOP 1111 1000 1001 ---- 1111 ------------ # PLD + LDRB_ri 1111 1000 1001 .... .... ............ @ldst_ri_pos + } + LDRB_ri 1111 1000 0001 .... .... 1..1 ........ @ldst_ri_idx + { + NOP 1111 1000 0001 ---- 1111 1100 -------- # PLD + LDRB_ri 1111 1000 0001 .... .... 1100 ........ @ldst_ri_neg + } + LDRBT_ri 1111 1000 0001 .... .... 1110 ........ @ldst_ri_unp + { + NOP 1111 1000 0001 ---- 1111 000000 -- ---- # PLD + LDRB_rr 1111 1000 0001 .... .... 000000 .. .... @ldst_rr + } +} +{ + { + NOP 1111 1000 -011 1111 1111 ------------ # PLD + LDRH_ri 1111 1000 .011 1111 .... ............ @ldst_ri_lit + } + { + NOP 1111 1000 1011 ---- 1111 ------------ # PLDW + LDRH_ri 1111 1000 1011 .... .... ............ @ldst_ri_pos + } + LDRH_ri 1111 1000 0011 .... .... 1..1 ........ @ldst_ri_idx + { + NOP 1111 1000 0011 ---- 1111 1100 -------- # PLDW + LDRH_ri 1111 1000 0011 .... .... 1100 ........ @ldst_ri_neg + } + LDRHT_ri 1111 1000 0011 .... .... 1110 ........ @ldst_ri_unp + { + NOP 1111 1000 0011 ---- 1111 000000 -- ---- # PLDW + LDRH_rr 1111 1000 0011 .... .... 000000 .. .... @ldst_rr + } +} +{ + LDR_ri 1111 1000 .101 1111 .... ............ @ldst_ri_lit + LDR_ri 1111 1000 1101 .... .... ............ @ldst_ri_pos + LDR_ri 1111 1000 0101 .... .... 1..1 ........ @ldst_ri_idx + LDR_ri 1111 1000 0101 .... .... 1100 ........ @ldst_ri_neg + LDRT_ri 1111 1000 0101 .... .... 1110 ........ @ldst_ri_unp + LDR_rr 1111 1000 0101 .... .... 000000 .. .... @ldst_rr +} +# NOPs here are PLI. +{ + { + NOP 1111 1001 -001 1111 1111 ------------ + LDRSB_ri 1111 1001 .001 1111 .... ............ @ldst_ri_lit + } + { + NOP 1111 1001 1001 ---- 1111 ------------ + LDRSB_ri 1111 1001 1001 .... .... ............ @ldst_ri_pos + } + LDRSB_ri 1111 1001 0001 .... .... 1..1 ........ @ldst_ri_idx + { + NOP 1111 1001 0001 ---- 1111 1100 -------- + LDRSB_ri 1111 1001 0001 .... .... 1100 ........ @ldst_ri_neg + } + LDRSBT_ri 1111 1001 0001 .... .... 1110 ........ @ldst_ri_unp + { + NOP 1111 1001 0001 ---- 1111 000000 -- ---- + LDRSB_rr 1111 1001 0001 .... .... 000000 .. .... @ldst_rr + } +} +# NOPs here are unallocated memory hints, treated as NOP. +{ + { + NOP 1111 1001 -011 1111 1111 ------------ + LDRSH_ri 1111 1001 .011 1111 .... ............ @ldst_ri_lit + } + { + NOP 1111 1001 1011 ---- 1111 ------------ + LDRSH_ri 1111 1001 1011 .... .... ............ @ldst_ri_pos + } + LDRSH_ri 1111 1001 0011 .... .... 1..1 ........ @ldst_ri_idx + { + NOP 1111 1001 0011 ---- 1111 1100 -------- + LDRSH_ri 1111 1001 0011 .... .... 1100 ........ @ldst_ri_neg + } + LDRSHT_ri 1111 1001 0011 .... .... 1110 ........ @ldst_ri_unp + { + NOP 1111 1001 0011 ---- 1111 000000 -- ---- + LDRSH_rr 1111 1001 0011 .... .... 000000 .. .... @ldst_rr + } +} + +%imm8x4 0:8 !function=times_4 +&ldst_ri2 p w u rn rt rt2 imm +@ldstd_ri8 .... .... u:1 ... rn:4 rt:4 rt2:4 ........ \ + &ldst_ri2 imm=%imm8x4 + +STRD_ri_t32 1110 1000 .110 .... .... .... ........ @ldstd_ri8 w=1 p=0 +LDRD_ri_t32 1110 1000 .111 .... .... .... ........ @ldstd_ri8 w=1 p=0 + +STRD_ri_t32 1110 1001 .100 .... .... .... ........ @ldstd_ri8 w=0 p=1 +LDRD_ri_t32 1110 1001 .101 .... .... .... ........ @ldstd_ri8 w=0 p=1 + +STRD_ri_t32 1110 1001 .110 .... .... .... ........ @ldstd_ri8 w=1 p=1 +{ + SG 1110 1001 0111 1111 1110 1001 01111111 + LDRD_ri_t32 1110 1001 .111 .... .... .... ........ @ldstd_ri8 w=1 p=1 +} + +# Load/Store Exclusive, Load-Acquire/Store-Release, and Table Branch + +@strex_i .... .... .... rn:4 rt:4 rd:4 .... .... \ + &strex rt2=15 imm=%imm8x4 +@strex_0 .... .... .... rn:4 rt:4 .... .... rd:4 \ + &strex rt2=15 imm=0 +@strex_d .... .... .... rn:4 rt:4 rt2:4 .... rd:4 \ + &strex imm=0 + +@ldrex_i .... .... .... rn:4 rt:4 .... .... .... \ + &ldrex rt2=15 imm=%imm8x4 +@ldrex_0 .... .... .... rn:4 rt:4 .... .... .... \ + &ldrex rt2=15 imm=0 +@ldrex_d .... .... .... rn:4 rt:4 rt2:4 .... .... \ + &ldrex imm=0 + +{ + TT 1110 1000 0100 rn:4 1111 rd:4 A:1 T:1 000000 + STREX 1110 1000 0100 .... .... .... .... .... @strex_i +} +STREXB 1110 1000 1100 .... .... 1111 0100 .... @strex_0 +STREXH 1110 1000 1100 .... .... 1111 0101 .... @strex_0 +STREXD_t32 1110 1000 1100 .... .... .... 0111 .... @strex_d + +STLEX 1110 1000 1100 .... .... 1111 1110 .... @strex_0 +STLEXB 1110 1000 1100 .... .... 1111 1100 .... @strex_0 +STLEXH 1110 1000 1100 .... .... 1111 1101 .... @strex_0 +STLEXD_t32 1110 1000 1100 .... .... .... 1111 .... @strex_d + +STL 1110 1000 1100 .... .... 1111 1010 1111 @ldrex_0 +STLB 1110 1000 1100 .... .... 1111 1000 1111 @ldrex_0 +STLH 1110 1000 1100 .... .... 1111 1001 1111 @ldrex_0 + +LDREX 1110 1000 0101 .... .... 1111 .... .... @ldrex_i +LDREXB 1110 1000 1101 .... .... 1111 0100 1111 @ldrex_0 +LDREXH 1110 1000 1101 .... .... 1111 0101 1111 @ldrex_0 +LDREXD_t32 1110 1000 1101 .... .... .... 0111 1111 @ldrex_d + +LDAEX 1110 1000 1101 .... .... 1111 1110 1111 @ldrex_0 +LDAEXB 1110 1000 1101 .... .... 1111 1100 1111 @ldrex_0 +LDAEXH 1110 1000 1101 .... .... 1111 1101 1111 @ldrex_0 +LDAEXD_t32 1110 1000 1101 .... .... .... 1111 1111 @ldrex_d + +LDA 1110 1000 1101 .... .... 1111 1010 1111 @ldrex_0 +LDAB 1110 1000 1101 .... .... 1111 1000 1111 @ldrex_0 +LDAH 1110 1000 1101 .... .... 1111 1001 1111 @ldrex_0 + +&tbranch rn rm +@tbranch .... .... .... rn:4 .... .... .... rm:4 &tbranch + +TBB 1110 1000 1101 .... 1111 0000 0000 .... @tbranch +TBH 1110 1000 1101 .... 1111 0000 0001 .... @tbranch + +# Parallel addition and subtraction + +SADD8 1111 1010 1000 .... 1111 .... 0000 .... @rndm +QADD8 1111 1010 1000 .... 1111 .... 0001 .... @rndm +SHADD8 1111 1010 1000 .... 1111 .... 0010 .... @rndm +UADD8 1111 1010 1000 .... 1111 .... 0100 .... @rndm +UQADD8 1111 1010 1000 .... 1111 .... 0101 .... @rndm +UHADD8 1111 1010 1000 .... 1111 .... 0110 .... @rndm + +SADD16 1111 1010 1001 .... 1111 .... 0000 .... @rndm +QADD16 1111 1010 1001 .... 1111 .... 0001 .... @rndm +SHADD16 1111 1010 1001 .... 1111 .... 0010 .... @rndm +UADD16 1111 1010 1001 .... 1111 .... 0100 .... @rndm +UQADD16 1111 1010 1001 .... 1111 .... 0101 .... @rndm +UHADD16 1111 1010 1001 .... 1111 .... 0110 .... @rndm + +SASX 1111 1010 1010 .... 1111 .... 0000 .... @rndm +QASX 1111 1010 1010 .... 1111 .... 0001 .... @rndm +SHASX 1111 1010 1010 .... 1111 .... 0010 .... @rndm +UASX 1111 1010 1010 .... 1111 .... 0100 .... @rndm +UQASX 1111 1010 1010 .... 1111 .... 0101 .... @rndm +UHASX 1111 1010 1010 .... 1111 .... 0110 .... @rndm + +SSUB8 1111 1010 1100 .... 1111 .... 0000 .... @rndm +QSUB8 1111 1010 1100 .... 1111 .... 0001 .... @rndm +SHSUB8 1111 1010 1100 .... 1111 .... 0010 .... @rndm +USUB8 1111 1010 1100 .... 1111 .... 0100 .... @rndm +UQSUB8 1111 1010 1100 .... 1111 .... 0101 .... @rndm +UHSUB8 1111 1010 1100 .... 1111 .... 0110 .... @rndm + +SSUB16 1111 1010 1101 .... 1111 .... 0000 .... @rndm +QSUB16 1111 1010 1101 .... 1111 .... 0001 .... @rndm +SHSUB16 1111 1010 1101 .... 1111 .... 0010 .... @rndm +USUB16 1111 1010 1101 .... 1111 .... 0100 .... @rndm +UQSUB16 1111 1010 1101 .... 1111 .... 0101 .... @rndm +UHSUB16 1111 1010 1101 .... 1111 .... 0110 .... @rndm + +SSAX 1111 1010 1110 .... 1111 .... 0000 .... @rndm +QSAX 1111 1010 1110 .... 1111 .... 0001 .... @rndm +SHSAX 1111 1010 1110 .... 1111 .... 0010 .... @rndm +USAX 1111 1010 1110 .... 1111 .... 0100 .... @rndm +UQSAX 1111 1010 1110 .... 1111 .... 0101 .... @rndm +UHSAX 1111 1010 1110 .... 1111 .... 0110 .... @rndm + +# Register extends + +@rrr_rot .... .... .... rn:4 .... rd:4 .. rot:2 rm:4 &rrr_rot + +SXTAH 1111 1010 0000 .... 1111 .... 10.. .... @rrr_rot +UXTAH 1111 1010 0001 .... 1111 .... 10.. .... @rrr_rot +SXTAB16 1111 1010 0010 .... 1111 .... 10.. .... @rrr_rot +UXTAB16 1111 1010 0011 .... 1111 .... 10.. .... @rrr_rot +SXTAB 1111 1010 0100 .... 1111 .... 10.. .... @rrr_rot +UXTAB 1111 1010 0101 .... 1111 .... 10.. .... @rrr_rot + +# Load/store multiple + +@ldstm .... .... .. w:1 . rn:4 list:16 &ldst_block u=0 + +STM_t32 1110 1000 10.0 .... ................ @ldstm i=1 b=0 +STM_t32 1110 1001 00.0 .... ................ @ldstm i=0 b=1 +LDM_t32 1110 1000 10.1 .... ................ @ldstm i=1 b=0 +LDM_t32 1110 1001 00.1 .... ................ @ldstm i=0 b=1 + +&rfe !extern rn w pu +@rfe .... .... .. w:1 . rn:4 ................ &rfe + +RFE 1110 1000 00.1 .... 1100000000000000 @rfe pu=2 +RFE 1110 1001 10.1 .... 1100000000000000 @rfe pu=1 + +&srs !extern mode w pu +@srs .... .... .. w:1 . .... ........... mode:5 &srs + +SRS 1110 1000 00.0 1101 1100 0000 000. .... @srs pu=2 +SRS 1110 1001 10.0 1101 1100 0000 000. .... @srs pu=1 + +# Branches + +%imm24 26:s1 13:1 11:1 16:10 0:11 !function=t32_branch24 +@branch24 ................................ &i imm=%imm24 + +B 1111 0. .......... 10.1 ............ @branch24 +BL 1111 0. .......... 11.1 ............ @branch24 +BLX_i 1111 0. .......... 11.0 ............ @branch24 diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 6fd0b779d3..2d6cd09634 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -85,7 +85,7 @@ typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64); typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr); typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32); typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); -typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, TCGMemOp); +typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, MemOp); /* initialize TCG globals. */ void a64_translate_init(void) @@ -338,6 +338,13 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) } } +void unallocated_encoding(DisasContext *s) +{ + /* Unallocated and reserved encodings are uncategorized */ + gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(), + default_exception_el(s)); +} + static void init_tmp_a64_array(DisasContext *s) { #ifdef CONFIG_DEBUG_TCG @@ -433,7 +440,7 @@ TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf) * Dn, Sn, Hn or Bn). * (Note that this is not the same mapping as for A32; see cpu.h) */ -static inline int fp_reg_offset(DisasContext *s, int regno, TCGMemOp size) +static inline int fp_reg_offset(DisasContext *s, int regno, MemOp size) { return vec_reg_offset(s, regno, 0, size); } @@ -849,7 +856,7 @@ static void do_gpr_ld_memidx(DisasContext *s, bool iss_valid, unsigned int iss_srt, bool iss_sf, bool iss_ar) { - TCGMemOp memop = s->be_data + size; + MemOp memop = s->be_data + size; g_assert(size <= 3); @@ -926,7 +933,7 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size) TCGv_i64 tmphi; if (size < 4) { - TCGMemOp memop = s->be_data + size; + MemOp memop = s->be_data + size; tmphi = tcg_const_i64(0); tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop); } else { @@ -967,7 +974,7 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size) /* Get value of an element within a vector register */ static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx, - int element, TCGMemOp memop) + int element, MemOp memop) { int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE); switch (memop) { @@ -999,7 +1006,7 @@ static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx, } static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx, - int element, TCGMemOp memop) + int element, MemOp memop) { int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE); switch (memop) { @@ -1026,7 +1033,7 @@ static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx, /* Set value of an element within a vector register */ static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx, - int element, TCGMemOp memop) + int element, MemOp memop) { int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE); switch (memop) { @@ -1048,7 +1055,7 @@ static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx, } static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src, - int destidx, int element, TCGMemOp memop) + int destidx, int element, MemOp memop) { int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE); switch (memop) { @@ -1068,7 +1075,7 @@ static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src, /* Store from vector register to memory */ static void do_vec_st(DisasContext *s, int srcidx, int element, - TCGv_i64 tcg_addr, int size, TCGMemOp endian) + TCGv_i64 tcg_addr, int size, MemOp endian) { TCGv_i64 tcg_tmp = tcg_temp_new_i64(); @@ -1080,7 +1087,7 @@ static void do_vec_st(DisasContext *s, int srcidx, int element, /* Load from memory to vector register */ static void do_vec_ld(DisasContext *s, int destidx, int element, - TCGv_i64 tcg_addr, int size, TCGMemOp endian) + TCGv_i64 tcg_addr, int size, MemOp endian) { TCGv_i64 tcg_tmp = tcg_temp_new_i64(); @@ -1707,6 +1714,12 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, tcg_temp_free_ptr(tmpptr); tcg_temp_free_i32(tcg_syn); tcg_temp_free_i32(tcg_isread); + } else if (ri->type & ARM_CP_RAISES_EXC) { + /* + * The readfn or writefn might raise an exception; + * synchronize the CPU state in case it does. + */ + gen_a64_set_pc_im(s->pc_curr); } /* Handle special cases first */ @@ -2176,7 +2189,7 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, TCGv_i64 addr, int size, bool is_pair) { int idx = get_mem_index(s); - TCGMemOp memop = s->be_data; + MemOp memop = s->be_data; g_assert(size <= 3); if (is_pair) { @@ -3262,7 +3275,7 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) bool is_postidx = extract32(insn, 23, 1); bool is_q = extract32(insn, 30, 1); TCGv_i64 clean_addr, tcg_rn, tcg_ebytes; - TCGMemOp endian = s->be_data; + MemOp endian = s->be_data; int ebytes; /* bytes per element */ int elements; /* elements per vector */ @@ -5431,7 +5444,7 @@ static void disas_fp_csel(DisasContext *s, uint32_t insn) unsigned int mos, type, rm, cond, rn, rd; TCGv_i64 t_true, t_false, t_zero; DisasCompare64 c; - TCGMemOp sz; + MemOp sz; mos = extract32(insn, 29, 3); type = extract32(insn, 22, 2); @@ -6243,7 +6256,7 @@ static void disas_fp_imm(DisasContext *s, uint32_t insn) int mos = extract32(insn, 29, 3); uint64_t imm; TCGv_i64 tcg_res; - TCGMemOp sz; + MemOp sz; if (mos || imm5) { unallocated_encoding(s); @@ -7006,7 +7019,7 @@ static TCGv_i32 do_reduction_op(DisasContext *s, int fpopcode, int rn, { if (esize == size) { int element; - TCGMemOp msize = esize == 16 ? MO_16 : MO_32; + MemOp msize = esize == 16 ? MO_16 : MO_32; TCGv_i32 tcg_elem; /* We should have one register left here */ @@ -7998,7 +8011,7 @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, int shift = (2 * esize) - immhb; int elements = is_scalar ? 1 : (64 / esize); bool round = extract32(opcode, 0, 1); - TCGMemOp ldop = (size + 1) | (is_u_shift ? 0 : MO_SIGN); + MemOp ldop = (size + 1) | (is_u_shift ? 0 : MO_SIGN); TCGv_i64 tcg_rn, tcg_rd, tcg_round; TCGv_i32 tcg_rd_narrowed; TCGv_i64 tcg_final; @@ -8157,7 +8170,7 @@ static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q, } }; NeonGenTwoOpEnvFn *genfn = fns[src_unsigned][dst_unsigned][size]; - TCGMemOp memop = scalar ? size : MO_32; + MemOp memop = scalar ? size : MO_32; int maxpass = scalar ? 1 : is_q ? 4 : 2; for (pass = 0; pass < maxpass; pass++) { @@ -8201,7 +8214,7 @@ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, TCGv_ptr tcg_fpst = get_fpstatus_ptr(size == MO_16); TCGv_i32 tcg_shift = NULL; - TCGMemOp mop = size | (is_signed ? MO_SIGN : 0); + MemOp mop = size | (is_signed ? MO_SIGN : 0); int pass; if (fracbits || size == MO_64) { @@ -9980,7 +9993,7 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, int dsize = is_q ? 128 : 64; int esize = 8 << size; int elements = dsize/esize; - TCGMemOp memop = size | (is_u ? 0 : MO_SIGN); + MemOp memop = size | (is_u ? 0 : MO_SIGN); TCGv_i64 tcg_rn = new_tmp_a64(s); TCGv_i64 tcg_rd = new_tmp_a64(s); TCGv_i64 tcg_round; @@ -10323,7 +10336,7 @@ static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size, TCGv_i64 tcg_op1 = tcg_temp_new_i64(); TCGv_i64 tcg_op2 = tcg_temp_new_i64(); TCGv_i64 tcg_passres; - TCGMemOp memop = MO_32 | (is_u ? 0 : MO_SIGN); + MemOp memop = MO_32 | (is_u ? 0 : MO_SIGN); int elt = pass + is_q * 2; @@ -11803,7 +11816,7 @@ static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u, if (size == 2) { /* 32 + 32 -> 64 op */ - TCGMemOp memop = size + (u ? 0 : MO_SIGN); + MemOp memop = size + (u ? 0 : MO_SIGN); for (pass = 0; pass < maxpass; pass++) { TCGv_i64 tcg_op1 = tcg_temp_new_i64(); @@ -12825,7 +12838,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) switch (is_fp) { case 1: /* normal fp */ - /* convert insn encoded size to TCGMemOp size */ + /* convert insn encoded size to MemOp size */ switch (size) { case 0: /* half-precision */ size = MO_16; @@ -12873,7 +12886,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) return; } - /* Given TCGMemOp size, adjust register and indexing. */ + /* Given MemOp size, adjust register and indexing. */ switch (size) { case MO_16: index = h << 2 | l << 1 | m; @@ -13170,7 +13183,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) TCGv_i64 tcg_res[2]; int pass; bool satop = extract32(opcode, 0, 1); - TCGMemOp memop = MO_32; + MemOp memop = MO_32; if (satop || !u) { memop |= MO_SIGN; diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index 12ad8ac6ed..4c2c91ae1b 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -18,6 +18,8 @@ #ifndef TARGET_ARM_TRANSLATE_A64_H #define TARGET_ARM_TRANSLATE_A64_H +void unallocated_encoding(DisasContext *s); + #define unsupported_encoding(s, insn) \ do { \ qemu_log_mask(LOG_UNIMP, \ @@ -62,7 +64,7 @@ static inline void assert_fp_access_checked(DisasContext *s) * the FP/vector register Qn. */ static inline int vec_reg_offset(DisasContext *s, int regno, - int element, TCGMemOp size) + int element, MemOp size) { int element_size = 1 << size; int offs = element * element_size; diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index fa068b0e47..5d7edd0907 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4567,7 +4567,7 @@ static bool trans_STR_pri(DisasContext *s, arg_rri *a) */ /* The memory mode of the dtype. */ -static const TCGMemOp dtype_mop[16] = { +static const MemOp dtype_mop[16] = { MO_UB, MO_UB, MO_UB, MO_UB, MO_SL, MO_UW, MO_UW, MO_UW, MO_SW, MO_SW, MO_UL, MO_UL, diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c index 3e8ea80493..9ae980bef6 100644 --- a/target/arm/translate-vfp.inc.c +++ b/target/arm/translate-vfp.inc.c @@ -880,8 +880,10 @@ static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a) /* gpreg to fpreg */ tmp = load_reg(s, a->rt); neon_store_reg32(tmp, a->vm); + tcg_temp_free_i32(tmp); tmp = load_reg(s, a->rt2); neon_store_reg32(tmp, a->vm + 1); + tcg_temp_free_i32(tmp); } return true; diff --git a/target/arm/translate.c b/target/arm/translate.c index cbe19b7a62..34bb280e3d 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -114,7 +114,7 @@ typedef enum ISSInfo { } ISSInfo; /* Save the syndrome information for a Data Abort */ -static void disas_set_da_iss(DisasContext *s, TCGMemOp memop, ISSInfo issinfo) +static void disas_set_da_iss(DisasContext *s, MemOp memop, ISSInfo issinfo) { uint32_t syn; int sas = memop & MO_SIZE; @@ -355,7 +355,7 @@ static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b) } /* Byteswap each halfword. */ -static void gen_rev16(TCGv_i32 var) +static void gen_rev16(TCGv_i32 dest, TCGv_i32 var) { TCGv_i32 tmp = tcg_temp_new_i32(); TCGv_i32 mask = tcg_const_i32(0x00ff00ff); @@ -363,17 +363,17 @@ static void gen_rev16(TCGv_i32 var) tcg_gen_and_i32(tmp, tmp, mask); tcg_gen_and_i32(var, var, mask); tcg_gen_shli_i32(var, var, 8); - tcg_gen_or_i32(var, var, tmp); + tcg_gen_or_i32(dest, var, tmp); tcg_temp_free_i32(mask); tcg_temp_free_i32(tmp); } /* Byteswap low halfword and sign extend. */ -static void gen_revsh(TCGv_i32 var) +static void gen_revsh(TCGv_i32 dest, TCGv_i32 var) { tcg_gen_ext16u_i32(var, var); tcg_gen_bswap16_i32(var, var); - tcg_gen_ext16s_i32(var, var); + tcg_gen_ext16s_i32(dest, var); } /* 32x32->64 multiply. Marks inputs as dead. */ @@ -426,7 +426,7 @@ static void gen_swap_half(TCGv_i32 var) t0 = (t0 + t1) ^ tmp; */ -static void gen_add16(TCGv_i32 t0, TCGv_i32 t1) +static void gen_add16(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1) { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_xor_i32(tmp, t0, t1); @@ -434,15 +434,8 @@ static void gen_add16(TCGv_i32 t0, TCGv_i32 t1) tcg_gen_andi_i32(t0, t0, ~0x8000); tcg_gen_andi_i32(t1, t1, ~0x8000); tcg_gen_add_i32(t0, t0, t1); - tcg_gen_xor_i32(t0, t0, tmp); + tcg_gen_xor_i32(dest, t0, tmp); tcg_temp_free_i32(tmp); - tcg_temp_free_i32(t1); -} - -/* Set CF to the top bit of var. */ -static void gen_set_CF_bit31(TCGv_i32 var) -{ - tcg_gen_shri_i32(cpu_CF, var, 31); } /* Set N and Z flags from var. */ @@ -452,13 +445,6 @@ static inline void gen_logic_CC(TCGv_i32 var) tcg_gen_mov_i32(cpu_ZF, var); } -/* T0 += T1 + CF. */ -static void gen_adc(TCGv_i32 t0, TCGv_i32 t1) -{ - tcg_gen_add_i32(t0, t0, t1); - tcg_gen_add_i32(t0, t0, cpu_CF); -} - /* dest = T0 + T1 + CF. */ static void gen_add_carry(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1) { @@ -654,99 +640,6 @@ static inline void gen_arm_shift_reg(TCGv_i32 var, int shiftop, tcg_temp_free_i32(shift); } -#define PAS_OP(pfx) \ - switch (op2) { \ - case 0: gen_pas_helper(glue(pfx,add16)); break; \ - case 1: gen_pas_helper(glue(pfx,addsubx)); break; \ - case 2: gen_pas_helper(glue(pfx,subaddx)); break; \ - case 3: gen_pas_helper(glue(pfx,sub16)); break; \ - case 4: gen_pas_helper(glue(pfx,add8)); break; \ - case 7: gen_pas_helper(glue(pfx,sub8)); break; \ - } -static void gen_arm_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b) -{ - TCGv_ptr tmp; - - switch (op1) { -#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp) - case 1: - tmp = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE)); - PAS_OP(s) - tcg_temp_free_ptr(tmp); - break; - case 5: - tmp = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE)); - PAS_OP(u) - tcg_temp_free_ptr(tmp); - break; -#undef gen_pas_helper -#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b) - case 2: - PAS_OP(q); - break; - case 3: - PAS_OP(sh); - break; - case 6: - PAS_OP(uq); - break; - case 7: - PAS_OP(uh); - break; -#undef gen_pas_helper - } -} -#undef PAS_OP - -/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */ -#define PAS_OP(pfx) \ - switch (op1) { \ - case 0: gen_pas_helper(glue(pfx,add8)); break; \ - case 1: gen_pas_helper(glue(pfx,add16)); break; \ - case 2: gen_pas_helper(glue(pfx,addsubx)); break; \ - case 4: gen_pas_helper(glue(pfx,sub8)); break; \ - case 5: gen_pas_helper(glue(pfx,sub16)); break; \ - case 6: gen_pas_helper(glue(pfx,subaddx)); break; \ - } -static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b) -{ - TCGv_ptr tmp; - - switch (op2) { -#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp) - case 0: - tmp = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE)); - PAS_OP(s) - tcg_temp_free_ptr(tmp); - break; - case 4: - tmp = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE)); - PAS_OP(u) - tcg_temp_free_ptr(tmp); - break; -#undef gen_pas_helper -#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b) - case 1: - PAS_OP(q); - break; - case 2: - PAS_OP(sh); - break; - case 5: - PAS_OP(uq); - break; - case 6: - PAS_OP(uh); - break; -#undef gen_pas_helper - } -} -#undef PAS_OP - /* * Generate a conditional based on ARM condition code cc. * This is common between ARM and Aarch64 targets. @@ -857,25 +750,6 @@ void arm_gen_test_cc(int cc, TCGLabel *label) arm_free_cc(&cmp); } -static const uint8_t table_logic_cc[16] = { - 1, /* and */ - 1, /* xor */ - 0, /* sub */ - 0, /* rsb */ - 0, /* add */ - 0, /* adc */ - 0, /* sbc */ - 0, /* rsc */ - 1, /* andl */ - 1, /* xorl */ - 0, /* cmp */ - 0, /* cmn */ - 1, /* orr */ - 1, /* mov */ - 1, /* bic */ - 1, /* mvn */ -}; - static inline void gen_set_condexec(DisasContext *s) { if (s->condexec_mask) { @@ -891,21 +765,6 @@ static inline void gen_set_pc_im(DisasContext *s, target_ulong val) tcg_gen_movi_i32(cpu_R[15], val); } -/* Set PC and Thumb state from an immediate address. */ -static inline void gen_bx_im(DisasContext *s, uint32_t addr) -{ - TCGv_i32 tmp; - - s->base.is_jmp = DISAS_JUMP; - if (s->thumb != (addr & 1)) { - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, addr & 1); - tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, thumb)); - tcg_temp_free_i32(tmp); - } - tcg_gen_movi_i32(cpu_R[15], addr & ~1); -} - /* Set PC and Thumb state from var. var is marked as dead. */ static inline void gen_bx(DisasContext *s, TCGv_i32 var) { @@ -915,10 +774,27 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var) store_cpu_field(var, thumb); } -/* Set PC and Thumb state from var. var is marked as dead. +/* + * Set PC and Thumb state from var. var is marked as dead. * For M-profile CPUs, include logic to detect exception-return * branches and handle them. This is needed for Thumb POP/LDM to PC, LDR to PC, * and BX reg, and no others, and happens only for code in Handler mode. + * The Security Extension also requires us to check for the FNC_RETURN + * which signals a function return from non-secure state; this can happen + * in both Handler and Thread mode. + * To avoid having to do multiple comparisons in inline generated code, + * we make the check we do here loose, so it will match for EXC_RETURN + * in Thread mode. For system emulation do_v7m_exception_exit() checks + * for these spurious cases and returns without doing anything (giving + * the same behaviour as for a branch to a non-magic address). + * + * In linux-user mode it is unclear what the right behaviour for an + * attempted FNC_RETURN should be, because in real hardware this will go + * directly to Secure code (ie not the Linux kernel) which will then treat + * the error in any way it chooses. For QEMU we opt to make the FNC_RETURN + * attempt behave the way it would on a CPU without the security extension, + * which is to say "like a normal branch". That means we can simply treat + * all branches as normal with no magic address behaviour. */ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var) { @@ -926,10 +802,12 @@ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var) * s->base.is_jmp that we need to do the rest of the work later. */ gen_bx(s, var); +#ifndef CONFIG_USER_ONLY if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY) || (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M))) { s->base.is_jmp = DISAS_BX_EXCRET; } +#endif } static inline void gen_bx_excret_final_code(DisasContext *s) @@ -1042,7 +920,7 @@ static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var) * that the address argument is TCGv_i32 rather than TCGv. */ -static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, TCGMemOp op) +static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op) { TCGv addr = tcg_temp_new(); tcg_gen_extu_i32_tl(addr, a32); @@ -1055,7 +933,7 @@ static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, TCGMemOp op) } static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, - int index, TCGMemOp opc) + int index, MemOp opc) { TCGv addr; @@ -1070,7 +948,7 @@ static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, } static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, - int index, TCGMemOp opc) + int index, MemOp opc) { TCGv addr; @@ -1089,14 +967,6 @@ static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \ TCGv_i32 a32, int index) \ { \ gen_aa32_ld_i32(s, val, a32, index, OPC | s->be_data); \ -} \ -static inline void gen_aa32_ld##SUFF##_iss(DisasContext *s, \ - TCGv_i32 val, \ - TCGv_i32 a32, int index, \ - ISSInfo issinfo) \ -{ \ - gen_aa32_ld##SUFF(s, val, a32, index); \ - disas_set_da_iss(s, OPC, issinfo); \ } #define DO_GEN_ST(SUFF, OPC) \ @@ -1104,14 +974,6 @@ static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \ TCGv_i32 a32, int index) \ { \ gen_aa32_st_i32(s, val, a32, index, OPC | s->be_data); \ -} \ -static inline void gen_aa32_st##SUFF##_iss(DisasContext *s, \ - TCGv_i32 val, \ - TCGv_i32 a32, int index, \ - ISSInfo issinfo) \ -{ \ - gen_aa32_st##SUFF(s, val, a32, index); \ - disas_set_da_iss(s, OPC, issinfo | ISSIsWrite); \ } static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val) @@ -1123,7 +985,7 @@ static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val) } static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, - int index, TCGMemOp opc) + int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); tcg_gen_qemu_ld_i64(val, addr, index, opc); @@ -1138,7 +1000,7 @@ static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val, } static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, - int index, TCGMemOp opc) + int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); @@ -1160,9 +1022,7 @@ static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val, gen_aa32_st_i64(s, val, a32, index, MO_Q | s->be_data); } -DO_GEN_LD(8s, MO_SB) DO_GEN_LD(8u, MO_UB) -DO_GEN_LD(16s, MO_SW) DO_GEN_LD(16u, MO_UW) DO_GEN_LD(32u, MO_UL) DO_GEN_ST(8, MO_UB) @@ -1231,7 +1091,7 @@ static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn) s->base.is_jmp = DISAS_NORETURN; } -void unallocated_encoding(DisasContext *s) +static void unallocated_encoding(DisasContext *s) { /* Unallocated and reserved encodings are uncategorized */ gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(), @@ -1271,62 +1131,6 @@ static inline void gen_hlt(DisasContext *s, int imm) unallocated_encoding(s); } -static inline void gen_add_data_offset(DisasContext *s, unsigned int insn, - TCGv_i32 var) -{ - int val, rm, shift, shiftop; - TCGv_i32 offset; - - if (!(insn & (1 << 25))) { - /* immediate */ - val = insn & 0xfff; - if (!(insn & (1 << 23))) - val = -val; - if (val != 0) - tcg_gen_addi_i32(var, var, val); - } else { - /* shift/register */ - rm = (insn) & 0xf; - shift = (insn >> 7) & 0x1f; - shiftop = (insn >> 5) & 3; - offset = load_reg(s, rm); - gen_arm_shift_im(offset, shiftop, shift, 0); - if (!(insn & (1 << 23))) - tcg_gen_sub_i32(var, var, offset); - else - tcg_gen_add_i32(var, var, offset); - tcg_temp_free_i32(offset); - } -} - -static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, - int extra, TCGv_i32 var) -{ - int val, rm; - TCGv_i32 offset; - - if (insn & (1 << 22)) { - /* immediate */ - val = (insn & 0xf) | ((insn >> 4) & 0xf0); - if (!(insn & (1 << 23))) - val = -val; - val += extra; - if (val != 0) - tcg_gen_addi_i32(var, var, val); - } else { - /* register */ - if (extra) - tcg_gen_addi_i32(var, var, extra); - rm = (insn) & 0xf; - offset = load_reg(s, rm); - if (!(insn & (1 << 23))) - tcg_gen_sub_i32(var, var, offset); - else - tcg_gen_add_i32(var, var, offset); - tcg_temp_free_i32(offset); - } -} - static TCGv_ptr get_fpstatus_ptr(int neon) { TCGv_ptr statusptr = tcg_temp_new_ptr(); @@ -1369,7 +1173,7 @@ neon_reg_offset (int reg, int n) * where 0 is the least significant end of the register. */ static inline long -neon_element_offset(int reg, int element, TCGMemOp size) +neon_element_offset(int reg, int element, MemOp size) { int element_size = 1 << size; int ofs = element * element_size; @@ -1391,7 +1195,7 @@ static TCGv_i32 neon_load_reg(int reg, int pass) return tmp; } -static void neon_load_element(TCGv_i32 var, int reg, int ele, TCGMemOp mop) +static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) { long offset = neon_element_offset(reg, ele, mop & MO_SIZE); @@ -1410,7 +1214,7 @@ static void neon_load_element(TCGv_i32 var, int reg, int ele, TCGMemOp mop) } } -static void neon_load_element64(TCGv_i64 var, int reg, int ele, TCGMemOp mop) +static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) { long offset = neon_element_offset(reg, ele, mop & MO_SIZE); @@ -1438,7 +1242,7 @@ static void neon_store_reg(int reg, int pass, TCGv_i32 var) tcg_temp_free_i32(var); } -static void neon_store_element(int reg, int ele, TCGMemOp size, TCGv_i32 var) +static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) { long offset = neon_element_offset(reg, ele, size); @@ -1457,7 +1261,7 @@ static void neon_store_element(int reg, int ele, TCGMemOp size, TCGv_i32 var) } } -static void neon_store_element64(int reg, int ele, TCGMemOp size, TCGv_i64 var) +static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) { long offset = neon_element_offset(reg, ele, size); @@ -2906,9 +2710,8 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) { if (unlikely(is_singlestepping(s))) { /* An indirect jump so that we still trigger the debug exception. */ - if (s->thumb) - dest |= 1; - gen_bx_im(s, dest); + gen_set_pc_im(s, dest); + s->base.is_jmp = DISAS_JUMP; } else { gen_goto_tb(s, 0, dest); } @@ -3224,46 +3027,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc) gen_rfe(s, pc, load_cpu_field(spsr)); } -/* - * For WFI we will halt the vCPU until an IRQ. For WFE and YIELD we - * only call the helper when running single threaded TCG code to ensure - * the next round-robin scheduled vCPU gets a crack. In MTTCG mode we - * just skip this instruction. Currently the SEV/SEVL instructions - * which are *one* of many ways to wake the CPU from WFE are not - * implemented so we can't sleep like WFI does. - */ -static void gen_nop_hint(DisasContext *s, int val) -{ - switch (val) { - /* When running in MTTCG we don't generate jumps to the yield and - * WFE helpers as it won't affect the scheduling of other vCPUs. - * If we wanted to more completely model WFE/SEV so we don't busy - * spin unnecessarily we would need to do something more involved. - */ - case 1: /* yield */ - if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_set_pc_im(s, s->base.pc_next); - s->base.is_jmp = DISAS_YIELD; - } - break; - case 3: /* wfi */ - gen_set_pc_im(s, s->base.pc_next); - s->base.is_jmp = DISAS_WFI; - break; - case 2: /* wfe */ - if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_set_pc_im(s, s->base.pc_next); - s->base.is_jmp = DISAS_WFE; - } - break; - case 4: /* sev */ - case 5: /* sevl */ - /* TODO: Implement SEV, SEVL and WFE. May help SMP performance. */ - default: /* nop */ - break; - } -} - #define CPU_V001 cpu_V0, cpu_V0, cpu_V1 static inline void gen_neon_add(int size, TCGv_i32 t0, TCGv_i32 t1) @@ -3523,7 +3286,7 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) int n; int vec_size; int mmu_idx; - TCGMemOp endian; + MemOp endian; TCGv_i32 addr; TCGv_i32 tmp; TCGv_i32 tmp2; @@ -6511,7 +6274,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } break; case NEON_2RM_VREV16: - gen_rev16(tmp); + gen_rev16(tmp, tmp); break; case NEON_2RM_VCLS: switch (size) { @@ -6830,7 +6593,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } else if ((insn & 0x380) == 0) { /* VDUP */ int element; - TCGMemOp size; + MemOp size; if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) { return 1; @@ -7191,6 +6954,13 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(tmpptr); tcg_temp_free_i32(tcg_syn); tcg_temp_free_i32(tcg_isread); + } else if (ri->type & ARM_CP_RAISES_EXC) { + /* + * The readfn or writefn might raise an exception; + * synchronize the CPU state in case it does. + */ + gen_set_condexec(s); + gen_set_pc_im(s, s->pc_curr); } /* Handle special cases first */ @@ -7345,21 +7115,6 @@ static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val) store_reg(s, rhigh, tmp); } -/* load a 32-bit value from a register and perform a 64-bit accumulate. */ -static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow) -{ - TCGv_i64 tmp; - TCGv_i32 tmp2; - - /* Load value and extend to 64 bits. */ - tmp = tcg_temp_new_i64(); - tmp2 = load_reg(s, rlow); - tcg_gen_extu_i32_i64(tmp, tmp2); - tcg_temp_free_i32(tmp2); - tcg_gen_add_i64(val, val, tmp); - tcg_temp_free_i64(tmp); -} - /* load and add a 64-bit value from a register pair. */ static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh) { @@ -7395,7 +7150,7 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, TCGv_i32 addr, int size) { TCGv_i32 tmp = tcg_temp_new_i32(); - TCGMemOp opc = size | MO_ALIGN | s->be_data; + MemOp opc = size | MO_ALIGN | s->be_data; s->is_ldex = true; @@ -7449,7 +7204,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, TCGv taddr; TCGLabel *done_label; TCGLabel *fail_label; - TCGMemOp opc = size | MO_ALIGN | s->be_data; + MemOp opc = size | MO_ALIGN | s->be_data; /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) { [addr] = {Rt}; @@ -7657,14 +7412,3055 @@ static void arm_skip_unless(DisasContext *s, uint32_t cond) arm_gen_test_cc(cond ^ 1, s->condlabel); } -static void disas_arm_insn(DisasContext *s, unsigned int insn) + +/* + * Constant expanders for the decoders. + */ + +static int negate(DisasContext *s, int x) +{ + return -x; +} + +static int plus_2(DisasContext *s, int x) +{ + return x + 2; +} + +static int times_2(DisasContext *s, int x) +{ + return x * 2; +} + +static int times_4(DisasContext *s, int x) +{ + return x * 4; +} + +/* Return only the rotation part of T32ExpandImm. */ +static int t32_expandimm_rot(DisasContext *s, int x) +{ + return x & 0xc00 ? extract32(x, 7, 5) : 0; +} + +/* Return the unrotated immediate from T32ExpandImm. */ +static int t32_expandimm_imm(DisasContext *s, int x) +{ + int imm = extract32(x, 0, 8); + + switch (extract32(x, 8, 4)) { + case 0: /* XY */ + /* Nothing to do. */ + break; + case 1: /* 00XY00XY */ + imm *= 0x00010001; + break; + case 2: /* XY00XY00 */ + imm *= 0x01000100; + break; + case 3: /* XYXYXYXY */ + imm *= 0x01010101; + break; + default: + /* Rotated constant. */ + imm |= 0x80; + break; + } + return imm; +} + +static int t32_branch24(DisasContext *s, int x) +{ + /* Convert J1:J2 at x[22:21] to I2:I1, which involves I=J^~S. */ + x ^= !(x < 0) * (3 << 21); + /* Append the final zero. */ + return x << 1; +} + +static int t16_setflags(DisasContext *s) +{ + return s->condexec_mask == 0; +} + +static int t16_push_list(DisasContext *s, int x) +{ + return (x & 0xff) | (x & 0x100) << (14 - 8); +} + +static int t16_pop_list(DisasContext *s, int x) +{ + return (x & 0xff) | (x & 0x100) << (15 - 8); +} + +/* + * Include the generated decoders. + */ + +#include "decode-a32.inc.c" +#include "decode-a32-uncond.inc.c" +#include "decode-t32.inc.c" +#include "decode-t16.inc.c" + +/* Helpers to swap operands for reverse-subtract. */ +static void gen_rsb(TCGv_i32 dst, TCGv_i32 a, TCGv_i32 b) +{ + tcg_gen_sub_i32(dst, b, a); +} + +static void gen_rsb_CC(TCGv_i32 dst, TCGv_i32 a, TCGv_i32 b) +{ + gen_sub_CC(dst, b, a); +} + +static void gen_rsc(TCGv_i32 dest, TCGv_i32 a, TCGv_i32 b) +{ + gen_sub_carry(dest, b, a); +} + +static void gen_rsc_CC(TCGv_i32 dest, TCGv_i32 a, TCGv_i32 b) +{ + gen_sbc_CC(dest, b, a); +} + +/* + * Helpers for the data processing routines. + * + * After the computation store the results back. + * This may be suppressed altogether (STREG_NONE), require a runtime + * check against the stack limits (STREG_SP_CHECK), or generate an + * exception return. Oh, or store into a register. + * + * Always return true, indicating success for a trans_* function. + */ +typedef enum { + STREG_NONE, + STREG_NORMAL, + STREG_SP_CHECK, + STREG_EXC_RET, +} StoreRegKind; + +static bool store_reg_kind(DisasContext *s, int rd, + TCGv_i32 val, StoreRegKind kind) +{ + switch (kind) { + case STREG_NONE: + tcg_temp_free_i32(val); + return true; + case STREG_NORMAL: + /* See ALUWritePC: Interworking only from a32 mode. */ + if (s->thumb) { + store_reg(s, rd, val); + } else { + store_reg_bx(s, rd, val); + } + return true; + case STREG_SP_CHECK: + store_sp_checked(s, val); + return true; + case STREG_EXC_RET: + gen_exception_return(s, val); + return true; + } + g_assert_not_reached(); +} + +/* + * Data Processing (register) + * + * Operate, with set flags, one register source, + * one immediate shifted register source, and a destination. + */ +static bool op_s_rrr_shi(DisasContext *s, arg_s_rrr_shi *a, + void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32), + int logic_cc, StoreRegKind kind) +{ + TCGv_i32 tmp1, tmp2; + + tmp2 = load_reg(s, a->rm); + gen_arm_shift_im(tmp2, a->shty, a->shim, logic_cc); + tmp1 = load_reg(s, a->rn); + + gen(tmp1, tmp1, tmp2); + tcg_temp_free_i32(tmp2); + + if (logic_cc) { + gen_logic_CC(tmp1); + } + return store_reg_kind(s, a->rd, tmp1, kind); +} + +static bool op_s_rxr_shi(DisasContext *s, arg_s_rrr_shi *a, + void (*gen)(TCGv_i32, TCGv_i32), + int logic_cc, StoreRegKind kind) { - unsigned int cond, val, op1, i, shift, rm, rs, rn, rd, sh; TCGv_i32 tmp; - TCGv_i32 tmp2; - TCGv_i32 tmp3; + + tmp = load_reg(s, a->rm); + gen_arm_shift_im(tmp, a->shty, a->shim, logic_cc); + + gen(tmp, tmp); + if (logic_cc) { + gen_logic_CC(tmp); + } + return store_reg_kind(s, a->rd, tmp, kind); +} + +/* + * Data-processing (register-shifted register) + * + * Operate, with set flags, one register source, + * one register shifted register source, and a destination. + */ +static bool op_s_rrr_shr(DisasContext *s, arg_s_rrr_shr *a, + void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32), + int logic_cc, StoreRegKind kind) +{ + TCGv_i32 tmp1, tmp2; + + tmp1 = load_reg(s, a->rs); + tmp2 = load_reg(s, a->rm); + gen_arm_shift_reg(tmp2, a->shty, tmp1, logic_cc); + tmp1 = load_reg(s, a->rn); + + gen(tmp1, tmp1, tmp2); + tcg_temp_free_i32(tmp2); + + if (logic_cc) { + gen_logic_CC(tmp1); + } + return store_reg_kind(s, a->rd, tmp1, kind); +} + +static bool op_s_rxr_shr(DisasContext *s, arg_s_rrr_shr *a, + void (*gen)(TCGv_i32, TCGv_i32), + int logic_cc, StoreRegKind kind) +{ + TCGv_i32 tmp1, tmp2; + + tmp1 = load_reg(s, a->rs); + tmp2 = load_reg(s, a->rm); + gen_arm_shift_reg(tmp2, a->shty, tmp1, logic_cc); + + gen(tmp2, tmp2); + if (logic_cc) { + gen_logic_CC(tmp2); + } + return store_reg_kind(s, a->rd, tmp2, kind); +} + +/* + * Data-processing (immediate) + * + * Operate, with set flags, one register source, + * one rotated immediate, and a destination. + * + * Note that logic_cc && a->rot setting CF based on the msb of the + * immediate is the reason why we must pass in the unrotated form + * of the immediate. + */ +static bool op_s_rri_rot(DisasContext *s, arg_s_rri_rot *a, + void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32), + int logic_cc, StoreRegKind kind) +{ + TCGv_i32 tmp1, tmp2; + uint32_t imm; + + imm = ror32(a->imm, a->rot); + if (logic_cc && a->rot) { + tcg_gen_movi_i32(cpu_CF, imm >> 31); + } + tmp2 = tcg_const_i32(imm); + tmp1 = load_reg(s, a->rn); + + gen(tmp1, tmp1, tmp2); + tcg_temp_free_i32(tmp2); + + if (logic_cc) { + gen_logic_CC(tmp1); + } + return store_reg_kind(s, a->rd, tmp1, kind); +} + +static bool op_s_rxi_rot(DisasContext *s, arg_s_rri_rot *a, + void (*gen)(TCGv_i32, TCGv_i32), + int logic_cc, StoreRegKind kind) +{ + TCGv_i32 tmp; + uint32_t imm; + + imm = ror32(a->imm, a->rot); + if (logic_cc && a->rot) { + tcg_gen_movi_i32(cpu_CF, imm >> 31); + } + tmp = tcg_const_i32(imm); + + gen(tmp, tmp); + if (logic_cc) { + gen_logic_CC(tmp); + } + return store_reg_kind(s, a->rd, tmp, kind); +} + +#define DO_ANY3(NAME, OP, L, K) \ + static bool trans_##NAME##_rrri(DisasContext *s, arg_s_rrr_shi *a) \ + { StoreRegKind k = (K); return op_s_rrr_shi(s, a, OP, L, k); } \ + static bool trans_##NAME##_rrrr(DisasContext *s, arg_s_rrr_shr *a) \ + { StoreRegKind k = (K); return op_s_rrr_shr(s, a, OP, L, k); } \ + static bool trans_##NAME##_rri(DisasContext *s, arg_s_rri_rot *a) \ + { StoreRegKind k = (K); return op_s_rri_rot(s, a, OP, L, k); } + +#define DO_ANY2(NAME, OP, L, K) \ + static bool trans_##NAME##_rxri(DisasContext *s, arg_s_rrr_shi *a) \ + { StoreRegKind k = (K); return op_s_rxr_shi(s, a, OP, L, k); } \ + static bool trans_##NAME##_rxrr(DisasContext *s, arg_s_rrr_shr *a) \ + { StoreRegKind k = (K); return op_s_rxr_shr(s, a, OP, L, k); } \ + static bool trans_##NAME##_rxi(DisasContext *s, arg_s_rri_rot *a) \ + { StoreRegKind k = (K); return op_s_rxi_rot(s, a, OP, L, k); } + +#define DO_CMP2(NAME, OP, L) \ + static bool trans_##NAME##_xrri(DisasContext *s, arg_s_rrr_shi *a) \ + { return op_s_rrr_shi(s, a, OP, L, STREG_NONE); } \ + static bool trans_##NAME##_xrrr(DisasContext *s, arg_s_rrr_shr *a) \ + { return op_s_rrr_shr(s, a, OP, L, STREG_NONE); } \ + static bool trans_##NAME##_xri(DisasContext *s, arg_s_rri_rot *a) \ + { return op_s_rri_rot(s, a, OP, L, STREG_NONE); } + +DO_ANY3(AND, tcg_gen_and_i32, a->s, STREG_NORMAL) +DO_ANY3(EOR, tcg_gen_xor_i32, a->s, STREG_NORMAL) +DO_ANY3(ORR, tcg_gen_or_i32, a->s, STREG_NORMAL) +DO_ANY3(BIC, tcg_gen_andc_i32, a->s, STREG_NORMAL) + +DO_ANY3(RSB, a->s ? gen_rsb_CC : gen_rsb, false, STREG_NORMAL) +DO_ANY3(ADC, a->s ? gen_adc_CC : gen_add_carry, false, STREG_NORMAL) +DO_ANY3(SBC, a->s ? gen_sbc_CC : gen_sub_carry, false, STREG_NORMAL) +DO_ANY3(RSC, a->s ? gen_rsc_CC : gen_rsc, false, STREG_NORMAL) + +DO_CMP2(TST, tcg_gen_and_i32, true) +DO_CMP2(TEQ, tcg_gen_xor_i32, true) +DO_CMP2(CMN, gen_add_CC, false) +DO_CMP2(CMP, gen_sub_CC, false) + +DO_ANY3(ADD, a->s ? gen_add_CC : tcg_gen_add_i32, false, + a->rd == 13 && a->rn == 13 ? STREG_SP_CHECK : STREG_NORMAL) + +/* + * Note for the computation of StoreRegKind we return out of the + * middle of the functions that are expanded by DO_ANY3, and that + * we modify a->s via that parameter before it is used by OP. + */ +DO_ANY3(SUB, a->s ? gen_sub_CC : tcg_gen_sub_i32, false, + ({ + StoreRegKind ret = STREG_NORMAL; + if (a->rd == 15 && a->s) { + /* + * See ALUExceptionReturn: + * In User mode, UNPREDICTABLE; we choose UNDEF. + * In Hyp mode, UNDEFINED. + */ + if (IS_USER(s) || s->current_el == 2) { + unallocated_encoding(s); + return true; + } + /* There is no writeback of nzcv to PSTATE. */ + a->s = 0; + ret = STREG_EXC_RET; + } else if (a->rd == 13 && a->rn == 13) { + ret = STREG_SP_CHECK; + } + ret; + })) + +DO_ANY2(MOV, tcg_gen_mov_i32, a->s, + ({ + StoreRegKind ret = STREG_NORMAL; + if (a->rd == 15 && a->s) { + /* + * See ALUExceptionReturn: + * In User mode, UNPREDICTABLE; we choose UNDEF. + * In Hyp mode, UNDEFINED. + */ + if (IS_USER(s) || s->current_el == 2) { + unallocated_encoding(s); + return true; + } + /* There is no writeback of nzcv to PSTATE. */ + a->s = 0; + ret = STREG_EXC_RET; + } else if (a->rd == 13) { + ret = STREG_SP_CHECK; + } + ret; + })) + +DO_ANY2(MVN, tcg_gen_not_i32, a->s, STREG_NORMAL) + +/* + * ORN is only available with T32, so there is no register-shifted-register + * form of the insn. Using the DO_ANY3 macro would create an unused function. + */ +static bool trans_ORN_rrri(DisasContext *s, arg_s_rrr_shi *a) +{ + return op_s_rrr_shi(s, a, tcg_gen_orc_i32, a->s, STREG_NORMAL); +} + +static bool trans_ORN_rri(DisasContext *s, arg_s_rri_rot *a) +{ + return op_s_rri_rot(s, a, tcg_gen_orc_i32, a->s, STREG_NORMAL); +} + +#undef DO_ANY3 +#undef DO_ANY2 +#undef DO_CMP2 + +static bool trans_ADR(DisasContext *s, arg_ri *a) +{ + store_reg_bx(s, a->rd, add_reg_for_lit(s, 15, a->imm)); + return true; +} + +static bool trans_MOVW(DisasContext *s, arg_MOVW *a) +{ + TCGv_i32 tmp; + + if (!ENABLE_ARCH_6T2) { + return false; + } + + tmp = tcg_const_i32(a->imm); + store_reg(s, a->rd, tmp); + return true; +} + +static bool trans_MOVT(DisasContext *s, arg_MOVW *a) +{ + TCGv_i32 tmp; + + if (!ENABLE_ARCH_6T2) { + return false; + } + + tmp = load_reg(s, a->rd); + tcg_gen_ext16u_i32(tmp, tmp); + tcg_gen_ori_i32(tmp, tmp, a->imm << 16); + store_reg(s, a->rd, tmp); + return true; +} + +/* + * Multiply and multiply accumulate + */ + +static bool op_mla(DisasContext *s, arg_s_rrrr *a, bool add) +{ + TCGv_i32 t1, t2; + + t1 = load_reg(s, a->rn); + t2 = load_reg(s, a->rm); + tcg_gen_mul_i32(t1, t1, t2); + tcg_temp_free_i32(t2); + if (add) { + t2 = load_reg(s, a->ra); + tcg_gen_add_i32(t1, t1, t2); + tcg_temp_free_i32(t2); + } + if (a->s) { + gen_logic_CC(t1); + } + store_reg(s, a->rd, t1); + return true; +} + +static bool trans_MUL(DisasContext *s, arg_MUL *a) +{ + return op_mla(s, a, false); +} + +static bool trans_MLA(DisasContext *s, arg_MLA *a) +{ + return op_mla(s, a, true); +} + +static bool trans_MLS(DisasContext *s, arg_MLS *a) +{ + TCGv_i32 t1, t2; + + if (!ENABLE_ARCH_6T2) { + return false; + } + t1 = load_reg(s, a->rn); + t2 = load_reg(s, a->rm); + tcg_gen_mul_i32(t1, t1, t2); + tcg_temp_free_i32(t2); + t2 = load_reg(s, a->ra); + tcg_gen_sub_i32(t1, t2, t1); + tcg_temp_free_i32(t2); + store_reg(s, a->rd, t1); + return true; +} + +static bool op_mlal(DisasContext *s, arg_s_rrrr *a, bool uns, bool add) +{ + TCGv_i32 t0, t1, t2, t3; + + t0 = load_reg(s, a->rm); + t1 = load_reg(s, a->rn); + if (uns) { + tcg_gen_mulu2_i32(t0, t1, t0, t1); + } else { + tcg_gen_muls2_i32(t0, t1, t0, t1); + } + if (add) { + t2 = load_reg(s, a->ra); + t3 = load_reg(s, a->rd); + tcg_gen_add2_i32(t0, t1, t0, t1, t2, t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + if (a->s) { + gen_logicq_cc(t0, t1); + } + store_reg(s, a->ra, t0); + store_reg(s, a->rd, t1); + return true; +} + +static bool trans_UMULL(DisasContext *s, arg_UMULL *a) +{ + return op_mlal(s, a, true, false); +} + +static bool trans_SMULL(DisasContext *s, arg_SMULL *a) +{ + return op_mlal(s, a, false, false); +} + +static bool trans_UMLAL(DisasContext *s, arg_UMLAL *a) +{ + return op_mlal(s, a, true, true); +} + +static bool trans_SMLAL(DisasContext *s, arg_SMLAL *a) +{ + return op_mlal(s, a, false, true); +} + +static bool trans_UMAAL(DisasContext *s, arg_UMAAL *a) +{ + TCGv_i32 t0, t1, t2, zero; + + if (s->thumb + ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP) + : !ENABLE_ARCH_6) { + return false; + } + + t0 = load_reg(s, a->rm); + t1 = load_reg(s, a->rn); + tcg_gen_mulu2_i32(t0, t1, t0, t1); + zero = tcg_const_i32(0); + t2 = load_reg(s, a->ra); + tcg_gen_add2_i32(t0, t1, t0, t1, t2, zero); + tcg_temp_free_i32(t2); + t2 = load_reg(s, a->rd); + tcg_gen_add2_i32(t0, t1, t0, t1, t2, zero); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(zero); + store_reg(s, a->ra, t0); + store_reg(s, a->rd, t1); + return true; +} + +/* + * Saturating addition and subtraction + */ + +static bool op_qaddsub(DisasContext *s, arg_rrr *a, bool add, bool doub) +{ + TCGv_i32 t0, t1; + + if (s->thumb + ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP) + : !ENABLE_ARCH_5TE) { + return false; + } + + t0 = load_reg(s, a->rm); + t1 = load_reg(s, a->rn); + if (doub) { + gen_helper_add_saturate(t1, cpu_env, t1, t1); + } + if (add) { + gen_helper_add_saturate(t0, cpu_env, t0, t1); + } else { + gen_helper_sub_saturate(t0, cpu_env, t0, t1); + } + tcg_temp_free_i32(t1); + store_reg(s, a->rd, t0); + return true; +} + +#define DO_QADDSUB(NAME, ADD, DOUB) \ +static bool trans_##NAME(DisasContext *s, arg_rrr *a) \ +{ \ + return op_qaddsub(s, a, ADD, DOUB); \ +} + +DO_QADDSUB(QADD, true, false) +DO_QADDSUB(QSUB, false, false) +DO_QADDSUB(QDADD, true, true) +DO_QADDSUB(QDSUB, false, true) + +#undef DO_QADDSUB + +/* + * Halfword multiply and multiply accumulate + */ + +static bool op_smlaxxx(DisasContext *s, arg_rrrr *a, + int add_long, bool nt, bool mt) +{ + TCGv_i32 t0, t1, tl, th; + + if (s->thumb + ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP) + : !ENABLE_ARCH_5TE) { + return false; + } + + t0 = load_reg(s, a->rn); + t1 = load_reg(s, a->rm); + gen_mulxy(t0, t1, nt, mt); + tcg_temp_free_i32(t1); + + switch (add_long) { + case 0: + store_reg(s, a->rd, t0); + break; + case 1: + t1 = load_reg(s, a->ra); + gen_helper_add_setq(t0, cpu_env, t0, t1); + tcg_temp_free_i32(t1); + store_reg(s, a->rd, t0); + break; + case 2: + tl = load_reg(s, a->ra); + th = load_reg(s, a->rd); + t1 = tcg_const_i32(0); + tcg_gen_add2_i32(tl, th, tl, th, t0, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); + store_reg(s, a->ra, tl); + store_reg(s, a->rd, th); + break; + default: + g_assert_not_reached(); + } + return true; +} + +#define DO_SMLAX(NAME, add, nt, mt) \ +static bool trans_##NAME(DisasContext *s, arg_rrrr *a) \ +{ \ + return op_smlaxxx(s, a, add, nt, mt); \ +} + +DO_SMLAX(SMULBB, 0, 0, 0) +DO_SMLAX(SMULBT, 0, 0, 1) +DO_SMLAX(SMULTB, 0, 1, 0) +DO_SMLAX(SMULTT, 0, 1, 1) + +DO_SMLAX(SMLABB, 1, 0, 0) +DO_SMLAX(SMLABT, 1, 0, 1) +DO_SMLAX(SMLATB, 1, 1, 0) +DO_SMLAX(SMLATT, 1, 1, 1) + +DO_SMLAX(SMLALBB, 2, 0, 0) +DO_SMLAX(SMLALBT, 2, 0, 1) +DO_SMLAX(SMLALTB, 2, 1, 0) +DO_SMLAX(SMLALTT, 2, 1, 1) + +#undef DO_SMLAX + +static bool op_smlawx(DisasContext *s, arg_rrrr *a, bool add, bool mt) +{ + TCGv_i32 t0, t1; + + if (!ENABLE_ARCH_5TE) { + return false; + } + + t0 = load_reg(s, a->rn); + t1 = load_reg(s, a->rm); + /* + * Since the nominal result is product<47:16>, shift the 16-bit + * input up by 16 bits, so that the result is at product<63:32>. + */ + if (mt) { + tcg_gen_andi_i32(t1, t1, 0xffff0000); + } else { + tcg_gen_shli_i32(t1, t1, 16); + } + tcg_gen_muls2_i32(t0, t1, t0, t1); + tcg_temp_free_i32(t0); + if (add) { + t0 = load_reg(s, a->ra); + gen_helper_add_setq(t1, cpu_env, t1, t0); + tcg_temp_free_i32(t0); + } + store_reg(s, a->rd, t1); + return true; +} + +#define DO_SMLAWX(NAME, add, mt) \ +static bool trans_##NAME(DisasContext *s, arg_rrrr *a) \ +{ \ + return op_smlawx(s, a, add, mt); \ +} + +DO_SMLAWX(SMULWB, 0, 0) +DO_SMLAWX(SMULWT, 0, 1) +DO_SMLAWX(SMLAWB, 1, 0) +DO_SMLAWX(SMLAWT, 1, 1) + +#undef DO_SMLAWX + +/* + * MSR (immediate) and hints + */ + +static bool trans_YIELD(DisasContext *s, arg_YIELD *a) +{ + /* + * When running single-threaded TCG code, use the helper to ensure that + * the next round-robin scheduled vCPU gets a crack. When running in + * MTTCG we don't generate jumps to the helper as it won't affect the + * scheduling of other vCPUs. + */ + if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { + gen_set_pc_im(s, s->base.pc_next); + s->base.is_jmp = DISAS_YIELD; + } + return true; +} + +static bool trans_WFE(DisasContext *s, arg_WFE *a) +{ + /* + * When running single-threaded TCG code, use the helper to ensure that + * the next round-robin scheduled vCPU gets a crack. In MTTCG mode we + * just skip this instruction. Currently the SEV/SEVL instructions, + * which are *one* of many ways to wake the CPU from WFE, are not + * implemented so we can't sleep like WFI does. + */ + if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { + gen_set_pc_im(s, s->base.pc_next); + s->base.is_jmp = DISAS_WFE; + } + return true; +} + +static bool trans_WFI(DisasContext *s, arg_WFI *a) +{ + /* For WFI, halt the vCPU until an IRQ. */ + gen_set_pc_im(s, s->base.pc_next); + s->base.is_jmp = DISAS_WFI; + return true; +} + +static bool trans_NOP(DisasContext *s, arg_NOP *a) +{ + return true; +} + +static bool trans_MSR_imm(DisasContext *s, arg_MSR_imm *a) +{ + uint32_t val = ror32(a->imm, a->rot * 2); + uint32_t mask = msr_mask(s, a->mask, a->r); + + if (gen_set_psr_im(s, mask, a->r, val)) { + unallocated_encoding(s); + } + return true; +} + +/* + * Cyclic Redundancy Check + */ + +static bool op_crc32(DisasContext *s, arg_rrr *a, bool c, MemOp sz) +{ + TCGv_i32 t1, t2, t3; + + if (!dc_isar_feature(aa32_crc32, s)) { + return false; + } + + t1 = load_reg(s, a->rn); + t2 = load_reg(s, a->rm); + switch (sz) { + case MO_8: + gen_uxtb(t2); + break; + case MO_16: + gen_uxth(t2); + break; + case MO_32: + break; + default: + g_assert_not_reached(); + } + t3 = tcg_const_i32(1 << sz); + if (c) { + gen_helper_crc32c(t1, t1, t2, t3); + } else { + gen_helper_crc32(t1, t1, t2, t3); + } + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + store_reg(s, a->rd, t1); + return true; +} + +#define DO_CRC32(NAME, c, sz) \ +static bool trans_##NAME(DisasContext *s, arg_rrr *a) \ + { return op_crc32(s, a, c, sz); } + +DO_CRC32(CRC32B, false, MO_8) +DO_CRC32(CRC32H, false, MO_16) +DO_CRC32(CRC32W, false, MO_32) +DO_CRC32(CRC32CB, true, MO_8) +DO_CRC32(CRC32CH, true, MO_16) +DO_CRC32(CRC32CW, true, MO_32) + +#undef DO_CRC32 + +/* + * Miscellaneous instructions + */ + +static bool trans_MRS_bank(DisasContext *s, arg_MRS_bank *a) +{ + if (arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + gen_mrs_banked(s, a->r, a->sysm, a->rd); + return true; +} + +static bool trans_MSR_bank(DisasContext *s, arg_MSR_bank *a) +{ + if (arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + gen_msr_banked(s, a->r, a->sysm, a->rn); + return true; +} + +static bool trans_MRS_reg(DisasContext *s, arg_MRS_reg *a) +{ + TCGv_i32 tmp; + + if (arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + if (a->r) { + if (IS_USER(s)) { + unallocated_encoding(s); + return true; + } + tmp = load_cpu_field(spsr); + } else { + tmp = tcg_temp_new_i32(); + gen_helper_cpsr_read(tmp, cpu_env); + } + store_reg(s, a->rd, tmp); + return true; +} + +static bool trans_MSR_reg(DisasContext *s, arg_MSR_reg *a) +{ + TCGv_i32 tmp; + uint32_t mask = msr_mask(s, a->mask, a->r); + + if (arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + tmp = load_reg(s, a->rn); + if (gen_set_psr(s, mask, a->r, tmp)) { + unallocated_encoding(s); + } + return true; +} + +static bool trans_MRS_v7m(DisasContext *s, arg_MRS_v7m *a) +{ + TCGv_i32 tmp; + + if (!arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + tmp = tcg_const_i32(a->sysm); + gen_helper_v7m_mrs(tmp, cpu_env, tmp); + store_reg(s, a->rd, tmp); + return true; +} + +static bool trans_MSR_v7m(DisasContext *s, arg_MSR_v7m *a) +{ + TCGv_i32 addr, reg; + + if (!arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + addr = tcg_const_i32((a->mask << 10) | a->sysm); + reg = load_reg(s, a->rn); + gen_helper_v7m_msr(cpu_env, addr, reg); + tcg_temp_free_i32(addr); + tcg_temp_free_i32(reg); + gen_lookup_tb(s); + return true; +} + +static bool trans_BX(DisasContext *s, arg_BX *a) +{ + if (!ENABLE_ARCH_4T) { + return false; + } + gen_bx_excret(s, load_reg(s, a->rm)); + return true; +} + +static bool trans_BXJ(DisasContext *s, arg_BXJ *a) +{ + if (!ENABLE_ARCH_5J || arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + /* Trivial implementation equivalent to bx. */ + gen_bx(s, load_reg(s, a->rm)); + return true; +} + +static bool trans_BLX_r(DisasContext *s, arg_BLX_r *a) +{ + TCGv_i32 tmp; + + if (!ENABLE_ARCH_5) { + return false; + } + tmp = load_reg(s, a->rm); + tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb); + gen_bx(s, tmp); + return true; +} + +/* + * BXNS/BLXNS: only exist for v8M with the security extensions, + * and always UNDEF if NonSecure. We don't implement these in + * the user-only mode either (in theory you can use them from + * Secure User mode but they are too tied in to system emulation). + */ +static bool trans_BXNS(DisasContext *s, arg_BXNS *a) +{ + if (!s->v8m_secure || IS_USER_ONLY) { + unallocated_encoding(s); + } else { + gen_bxns(s, a->rm); + } + return true; +} + +static bool trans_BLXNS(DisasContext *s, arg_BLXNS *a) +{ + if (!s->v8m_secure || IS_USER_ONLY) { + unallocated_encoding(s); + } else { + gen_blxns(s, a->rm); + } + return true; +} + +static bool trans_CLZ(DisasContext *s, arg_CLZ *a) +{ + TCGv_i32 tmp; + + if (!ENABLE_ARCH_5) { + return false; + } + tmp = load_reg(s, a->rm); + tcg_gen_clzi_i32(tmp, tmp, 32); + store_reg(s, a->rd, tmp); + return true; +} + +static bool trans_ERET(DisasContext *s, arg_ERET *a) +{ + TCGv_i32 tmp; + + if (!arm_dc_feature(s, ARM_FEATURE_V7VE)) { + return false; + } + if (IS_USER(s)) { + unallocated_encoding(s); + return true; + } + if (s->current_el == 2) { + /* ERET from Hyp uses ELR_Hyp, not LR */ + tmp = load_cpu_field(elr_el[2]); + } else { + tmp = load_reg(s, 14); + } + gen_exception_return(s, tmp); + return true; +} + +static bool trans_HLT(DisasContext *s, arg_HLT *a) +{ + gen_hlt(s, a->imm); + return true; +} + +static bool trans_BKPT(DisasContext *s, arg_BKPT *a) +{ + if (!ENABLE_ARCH_5) { + return false; + } + gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false)); + return true; +} + +static bool trans_HVC(DisasContext *s, arg_HVC *a) +{ + if (!ENABLE_ARCH_7 || arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + if (IS_USER(s)) { + unallocated_encoding(s); + } else { + gen_hvc(s, a->imm); + } + return true; +} + +static bool trans_SMC(DisasContext *s, arg_SMC *a) +{ + if (!ENABLE_ARCH_6K || arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + if (IS_USER(s)) { + unallocated_encoding(s); + } else { + gen_smc(s); + } + return true; +} + +static bool trans_SG(DisasContext *s, arg_SG *a) +{ + if (!arm_dc_feature(s, ARM_FEATURE_M) || + !arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + /* + * SG (v8M only) + * The bulk of the behaviour for this instruction is implemented + * in v7m_handle_execute_nsc(), which deals with the insn when + * it is executed by a CPU in non-secure state from memory + * which is Secure & NonSecure-Callable. + * Here we only need to handle the remaining cases: + * * in NS memory (including the "security extension not + * implemented" case) : NOP + * * in S memory but CPU already secure (clear IT bits) + * We know that the attribute for the memory this insn is + * in must match the current CPU state, because otherwise + * get_phys_addr_pmsav8 would have generated an exception. + */ + if (s->v8m_secure) { + /* Like the IT insn, we don't need to generate any code */ + s->condexec_cond = 0; + s->condexec_mask = 0; + } + return true; +} + +static bool trans_TT(DisasContext *s, arg_TT *a) +{ + TCGv_i32 addr, tmp; + + if (!arm_dc_feature(s, ARM_FEATURE_M) || + !arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + if (a->rd == 13 || a->rd == 15 || a->rn == 15) { + /* We UNDEF for these UNPREDICTABLE cases */ + unallocated_encoding(s); + return true; + } + if (a->A && !s->v8m_secure) { + /* This case is UNDEFINED. */ + unallocated_encoding(s); + return true; + } + + addr = load_reg(s, a->rn); + tmp = tcg_const_i32((a->A << 1) | a->T); + gen_helper_v7m_tt(tmp, cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + store_reg(s, a->rd, tmp); + return true; +} + +/* + * Load/store register index + */ + +static ISSInfo make_issinfo(DisasContext *s, int rd, bool p, bool w) +{ + ISSInfo ret; + + /* ISS not valid if writeback */ + if (p && !w) { + ret = rd; + } else { + ret = ISSInvalid; + } + return ret; +} + +static TCGv_i32 op_addr_rr_pre(DisasContext *s, arg_ldst_rr *a) +{ + TCGv_i32 addr = load_reg(s, a->rn); + + if (s->v8m_stackcheck && a->rn == 13 && a->w) { + gen_helper_v8m_stackcheck(cpu_env, addr); + } + + if (a->p) { + TCGv_i32 ofs = load_reg(s, a->rm); + gen_arm_shift_im(ofs, a->shtype, a->shimm, 0); + if (a->u) { + tcg_gen_add_i32(addr, addr, ofs); + } else { + tcg_gen_sub_i32(addr, addr, ofs); + } + tcg_temp_free_i32(ofs); + } + return addr; +} + +static void op_addr_rr_post(DisasContext *s, arg_ldst_rr *a, + TCGv_i32 addr, int address_offset) +{ + if (!a->p) { + TCGv_i32 ofs = load_reg(s, a->rm); + gen_arm_shift_im(ofs, a->shtype, a->shimm, 0); + if (a->u) { + tcg_gen_add_i32(addr, addr, ofs); + } else { + tcg_gen_sub_i32(addr, addr, ofs); + } + tcg_temp_free_i32(ofs); + } else if (!a->w) { + tcg_temp_free_i32(addr); + return; + } + tcg_gen_addi_i32(addr, addr, address_offset); + store_reg(s, a->rn, addr); +} + +static bool op_load_rr(DisasContext *s, arg_ldst_rr *a, + MemOp mop, int mem_idx) +{ + ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w); + TCGv_i32 addr, tmp; + + addr = op_addr_rr_pre(s, a); + + tmp = tcg_temp_new_i32(); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, mop | s->be_data); + disas_set_da_iss(s, mop, issinfo); + + /* + * Perform base writeback before the loaded value to + * ensure correct behavior with overlapping index registers. + */ + op_addr_rr_post(s, a, addr, 0); + store_reg_from_load(s, a->rt, tmp); + return true; +} + +static bool op_store_rr(DisasContext *s, arg_ldst_rr *a, + MemOp mop, int mem_idx) +{ + ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w) | ISSIsWrite; + TCGv_i32 addr, tmp; + + addr = op_addr_rr_pre(s, a); + + tmp = load_reg(s, a->rt); + gen_aa32_st_i32(s, tmp, addr, mem_idx, mop | s->be_data); + disas_set_da_iss(s, mop, issinfo); + tcg_temp_free_i32(tmp); + + op_addr_rr_post(s, a, addr, 0); + return true; +} + +static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a) +{ + int mem_idx = get_mem_index(s); + TCGv_i32 addr, tmp; + + if (!ENABLE_ARCH_5TE) { + return false; + } + if (a->rt & 1) { + unallocated_encoding(s); + return true; + } + addr = op_addr_rr_pre(s, a); + + tmp = tcg_temp_new_i32(); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + store_reg(s, a->rt, tmp); + + tcg_gen_addi_i32(addr, addr, 4); + + tmp = tcg_temp_new_i32(); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + store_reg(s, a->rt + 1, tmp); + + /* LDRD w/ base writeback is undefined if the registers overlap. */ + op_addr_rr_post(s, a, addr, -4); + return true; +} + +static bool trans_STRD_rr(DisasContext *s, arg_ldst_rr *a) +{ + int mem_idx = get_mem_index(s); + TCGv_i32 addr, tmp; + + if (!ENABLE_ARCH_5TE) { + return false; + } + if (a->rt & 1) { + unallocated_encoding(s); + return true; + } + addr = op_addr_rr_pre(s, a); + + tmp = load_reg(s, a->rt); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + tcg_temp_free_i32(tmp); + + tcg_gen_addi_i32(addr, addr, 4); + + tmp = load_reg(s, a->rt + 1); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + tcg_temp_free_i32(tmp); + + op_addr_rr_post(s, a, addr, -4); + return true; +} + +/* + * Load/store immediate index + */ + +static TCGv_i32 op_addr_ri_pre(DisasContext *s, arg_ldst_ri *a) +{ + int ofs = a->imm; + + if (!a->u) { + ofs = -ofs; + } + + if (s->v8m_stackcheck && a->rn == 13 && a->w) { + /* + * Stackcheck. Here we know 'addr' is the current SP; + * U is set if we're moving SP up, else down. It is + * UNKNOWN whether the limit check triggers when SP starts + * below the limit and ends up above it; we chose to do so. + */ + if (!a->u) { + TCGv_i32 newsp = tcg_temp_new_i32(); + tcg_gen_addi_i32(newsp, cpu_R[13], ofs); + gen_helper_v8m_stackcheck(cpu_env, newsp); + tcg_temp_free_i32(newsp); + } else { + gen_helper_v8m_stackcheck(cpu_env, cpu_R[13]); + } + } + + return add_reg_for_lit(s, a->rn, a->p ? ofs : 0); +} + +static void op_addr_ri_post(DisasContext *s, arg_ldst_ri *a, + TCGv_i32 addr, int address_offset) +{ + if (!a->p) { + if (a->u) { + address_offset += a->imm; + } else { + address_offset -= a->imm; + } + } else if (!a->w) { + tcg_temp_free_i32(addr); + return; + } + tcg_gen_addi_i32(addr, addr, address_offset); + store_reg(s, a->rn, addr); +} + +static bool op_load_ri(DisasContext *s, arg_ldst_ri *a, + MemOp mop, int mem_idx) +{ + ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w); + TCGv_i32 addr, tmp; + + addr = op_addr_ri_pre(s, a); + + tmp = tcg_temp_new_i32(); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, mop | s->be_data); + disas_set_da_iss(s, mop, issinfo); + + /* + * Perform base writeback before the loaded value to + * ensure correct behavior with overlapping index registers. + */ + op_addr_ri_post(s, a, addr, 0); + store_reg_from_load(s, a->rt, tmp); + return true; +} + +static bool op_store_ri(DisasContext *s, arg_ldst_ri *a, + MemOp mop, int mem_idx) +{ + ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w) | ISSIsWrite; + TCGv_i32 addr, tmp; + + addr = op_addr_ri_pre(s, a); + + tmp = load_reg(s, a->rt); + gen_aa32_st_i32(s, tmp, addr, mem_idx, mop | s->be_data); + disas_set_da_iss(s, mop, issinfo); + tcg_temp_free_i32(tmp); + + op_addr_ri_post(s, a, addr, 0); + return true; +} + +static bool op_ldrd_ri(DisasContext *s, arg_ldst_ri *a, int rt2) +{ + int mem_idx = get_mem_index(s); + TCGv_i32 addr, tmp; + + addr = op_addr_ri_pre(s, a); + + tmp = tcg_temp_new_i32(); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + store_reg(s, a->rt, tmp); + + tcg_gen_addi_i32(addr, addr, 4); + + tmp = tcg_temp_new_i32(); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + store_reg(s, rt2, tmp); + + /* LDRD w/ base writeback is undefined if the registers overlap. */ + op_addr_ri_post(s, a, addr, -4); + return true; +} + +static bool trans_LDRD_ri_a32(DisasContext *s, arg_ldst_ri *a) +{ + if (!ENABLE_ARCH_5TE || (a->rt & 1)) { + return false; + } + return op_ldrd_ri(s, a, a->rt + 1); +} + +static bool trans_LDRD_ri_t32(DisasContext *s, arg_ldst_ri2 *a) +{ + arg_ldst_ri b = { + .u = a->u, .w = a->w, .p = a->p, + .rn = a->rn, .rt = a->rt, .imm = a->imm + }; + return op_ldrd_ri(s, &b, a->rt2); +} + +static bool op_strd_ri(DisasContext *s, arg_ldst_ri *a, int rt2) +{ + int mem_idx = get_mem_index(s); + TCGv_i32 addr, tmp; + + addr = op_addr_ri_pre(s, a); + + tmp = load_reg(s, a->rt); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + tcg_temp_free_i32(tmp); + + tcg_gen_addi_i32(addr, addr, 4); + + tmp = load_reg(s, rt2); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + tcg_temp_free_i32(tmp); + + op_addr_ri_post(s, a, addr, -4); + return true; +} + +static bool trans_STRD_ri_a32(DisasContext *s, arg_ldst_ri *a) +{ + if (!ENABLE_ARCH_5TE || (a->rt & 1)) { + return false; + } + return op_strd_ri(s, a, a->rt + 1); +} + +static bool trans_STRD_ri_t32(DisasContext *s, arg_ldst_ri2 *a) +{ + arg_ldst_ri b = { + .u = a->u, .w = a->w, .p = a->p, + .rn = a->rn, .rt = a->rt, .imm = a->imm + }; + return op_strd_ri(s, &b, a->rt2); +} + +#define DO_LDST(NAME, WHICH, MEMOP) \ +static bool trans_##NAME##_ri(DisasContext *s, arg_ldst_ri *a) \ +{ \ + return op_##WHICH##_ri(s, a, MEMOP, get_mem_index(s)); \ +} \ +static bool trans_##NAME##T_ri(DisasContext *s, arg_ldst_ri *a) \ +{ \ + return op_##WHICH##_ri(s, a, MEMOP, get_a32_user_mem_index(s)); \ +} \ +static bool trans_##NAME##_rr(DisasContext *s, arg_ldst_rr *a) \ +{ \ + return op_##WHICH##_rr(s, a, MEMOP, get_mem_index(s)); \ +} \ +static bool trans_##NAME##T_rr(DisasContext *s, arg_ldst_rr *a) \ +{ \ + return op_##WHICH##_rr(s, a, MEMOP, get_a32_user_mem_index(s)); \ +} + +DO_LDST(LDR, load, MO_UL) +DO_LDST(LDRB, load, MO_UB) +DO_LDST(LDRH, load, MO_UW) +DO_LDST(LDRSB, load, MO_SB) +DO_LDST(LDRSH, load, MO_SW) + +DO_LDST(STR, store, MO_UL) +DO_LDST(STRB, store, MO_UB) +DO_LDST(STRH, store, MO_UW) + +#undef DO_LDST + +/* + * Synchronization primitives + */ + +static bool op_swp(DisasContext *s, arg_SWP *a, MemOp opc) +{ + TCGv_i32 addr, tmp; + TCGv taddr; + + opc |= s->be_data; + addr = load_reg(s, a->rn); + taddr = gen_aa32_addr(s, addr, opc); + tcg_temp_free_i32(addr); + + tmp = load_reg(s, a->rt2); + tcg_gen_atomic_xchg_i32(tmp, taddr, tmp, get_mem_index(s), opc); + tcg_temp_free(taddr); + + store_reg(s, a->rt, tmp); + return true; +} + +static bool trans_SWP(DisasContext *s, arg_SWP *a) +{ + return op_swp(s, a, MO_UL | MO_ALIGN); +} + +static bool trans_SWPB(DisasContext *s, arg_SWP *a) +{ + return op_swp(s, a, MO_UB); +} + +/* + * Load/Store Exclusive and Load-Acquire/Store-Release + */ + +static bool op_strex(DisasContext *s, arg_STREX *a, MemOp mop, bool rel) +{ TCGv_i32 addr; - TCGv_i64 tmp64; + + /* We UNDEF for these UNPREDICTABLE cases. */ + if (a->rd == 15 || a->rn == 15 || a->rt == 15 + || a->rd == a->rn || a->rd == a->rt + || (s->thumb && (a->rd == 13 || a->rt == 13)) + || (mop == MO_64 + && (a->rt2 == 15 + || a->rd == a->rt2 || a->rt == a->rt2 + || (s->thumb && a->rt2 == 13)))) { + unallocated_encoding(s); + return true; + } + + if (rel) { + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + } + + addr = tcg_temp_local_new_i32(); + load_reg_var(s, addr, a->rn); + tcg_gen_addi_i32(addr, addr, a->imm); + + gen_store_exclusive(s, a->rd, a->rt, a->rt2, addr, mop); + tcg_temp_free_i32(addr); + return true; +} + +static bool trans_STREX(DisasContext *s, arg_STREX *a) +{ + if (!ENABLE_ARCH_6) { + return false; + } + return op_strex(s, a, MO_32, false); +} + +static bool trans_STREXD_a32(DisasContext *s, arg_STREX *a) +{ + if (!ENABLE_ARCH_6K) { + return false; + } + /* We UNDEF for these UNPREDICTABLE cases. */ + if (a->rt & 1) { + unallocated_encoding(s); + return true; + } + a->rt2 = a->rt + 1; + return op_strex(s, a, MO_64, false); +} + +static bool trans_STREXD_t32(DisasContext *s, arg_STREX *a) +{ + return op_strex(s, a, MO_64, false); +} + +static bool trans_STREXB(DisasContext *s, arg_STREX *a) +{ + if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) { + return false; + } + return op_strex(s, a, MO_8, false); +} + +static bool trans_STREXH(DisasContext *s, arg_STREX *a) +{ + if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) { + return false; + } + return op_strex(s, a, MO_16, false); +} + +static bool trans_STLEX(DisasContext *s, arg_STREX *a) +{ + if (!ENABLE_ARCH_8) { + return false; + } + return op_strex(s, a, MO_32, true); +} + +static bool trans_STLEXD_a32(DisasContext *s, arg_STREX *a) +{ + if (!ENABLE_ARCH_8) { + return false; + } + /* We UNDEF for these UNPREDICTABLE cases. */ + if (a->rt & 1) { + unallocated_encoding(s); + return true; + } + a->rt2 = a->rt + 1; + return op_strex(s, a, MO_64, true); +} + +static bool trans_STLEXD_t32(DisasContext *s, arg_STREX *a) +{ + if (!ENABLE_ARCH_8) { + return false; + } + return op_strex(s, a, MO_64, true); +} + +static bool trans_STLEXB(DisasContext *s, arg_STREX *a) +{ + if (!ENABLE_ARCH_8) { + return false; + } + return op_strex(s, a, MO_8, true); +} + +static bool trans_STLEXH(DisasContext *s, arg_STREX *a) +{ + if (!ENABLE_ARCH_8) { + return false; + } + return op_strex(s, a, MO_16, true); +} + +static bool op_stl(DisasContext *s, arg_STL *a, MemOp mop) +{ + TCGv_i32 addr, tmp; + + if (!ENABLE_ARCH_8) { + return false; + } + /* We UNDEF for these UNPREDICTABLE cases. */ + if (a->rn == 15 || a->rt == 15) { + unallocated_encoding(s); + return true; + } + + addr = load_reg(s, a->rn); + tmp = load_reg(s, a->rt); + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), mop | s->be_data); + disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel | ISSIsWrite); + + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(addr); + return true; +} + +static bool trans_STL(DisasContext *s, arg_STL *a) +{ + return op_stl(s, a, MO_UL); +} + +static bool trans_STLB(DisasContext *s, arg_STL *a) +{ + return op_stl(s, a, MO_UB); +} + +static bool trans_STLH(DisasContext *s, arg_STL *a) +{ + return op_stl(s, a, MO_UW); +} + +static bool op_ldrex(DisasContext *s, arg_LDREX *a, MemOp mop, bool acq) +{ + TCGv_i32 addr; + + /* We UNDEF for these UNPREDICTABLE cases. */ + if (a->rn == 15 || a->rt == 15 + || (s->thumb && a->rt == 13) + || (mop == MO_64 + && (a->rt2 == 15 || a->rt == a->rt2 + || (s->thumb && a->rt2 == 13)))) { + unallocated_encoding(s); + return true; + } + + addr = tcg_temp_local_new_i32(); + load_reg_var(s, addr, a->rn); + tcg_gen_addi_i32(addr, addr, a->imm); + + gen_load_exclusive(s, a->rt, a->rt2, addr, mop); + tcg_temp_free_i32(addr); + + if (acq) { + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); + } + return true; +} + +static bool trans_LDREX(DisasContext *s, arg_LDREX *a) +{ + if (!ENABLE_ARCH_6) { + return false; + } + return op_ldrex(s, a, MO_32, false); +} + +static bool trans_LDREXD_a32(DisasContext *s, arg_LDREX *a) +{ + if (!ENABLE_ARCH_6K) { + return false; + } + /* We UNDEF for these UNPREDICTABLE cases. */ + if (a->rt & 1) { + unallocated_encoding(s); + return true; + } + a->rt2 = a->rt + 1; + return op_ldrex(s, a, MO_64, false); +} + +static bool trans_LDREXD_t32(DisasContext *s, arg_LDREX *a) +{ + return op_ldrex(s, a, MO_64, false); +} + +static bool trans_LDREXB(DisasContext *s, arg_LDREX *a) +{ + if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) { + return false; + } + return op_ldrex(s, a, MO_8, false); +} + +static bool trans_LDREXH(DisasContext *s, arg_LDREX *a) +{ + if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) { + return false; + } + return op_ldrex(s, a, MO_16, false); +} + +static bool trans_LDAEX(DisasContext *s, arg_LDREX *a) +{ + if (!ENABLE_ARCH_8) { + return false; + } + return op_ldrex(s, a, MO_32, true); +} + +static bool trans_LDAEXD_a32(DisasContext *s, arg_LDREX *a) +{ + if (!ENABLE_ARCH_8) { + return false; + } + /* We UNDEF for these UNPREDICTABLE cases. */ + if (a->rt & 1) { + unallocated_encoding(s); + return true; + } + a->rt2 = a->rt + 1; + return op_ldrex(s, a, MO_64, true); +} + +static bool trans_LDAEXD_t32(DisasContext *s, arg_LDREX *a) +{ + if (!ENABLE_ARCH_8) { + return false; + } + return op_ldrex(s, a, MO_64, true); +} + +static bool trans_LDAEXB(DisasContext *s, arg_LDREX *a) +{ + if (!ENABLE_ARCH_8) { + return false; + } + return op_ldrex(s, a, MO_8, true); +} + +static bool trans_LDAEXH(DisasContext *s, arg_LDREX *a) +{ + if (!ENABLE_ARCH_8) { + return false; + } + return op_ldrex(s, a, MO_16, true); +} + +static bool op_lda(DisasContext *s, arg_LDA *a, MemOp mop) +{ + TCGv_i32 addr, tmp; + + if (!ENABLE_ARCH_8) { + return false; + } + /* We UNDEF for these UNPREDICTABLE cases. */ + if (a->rn == 15 || a->rt == 15) { + unallocated_encoding(s); + return true; + } + + addr = load_reg(s, a->rn); + tmp = tcg_temp_new_i32(); + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop | s->be_data); + disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel); + tcg_temp_free_i32(addr); + + store_reg(s, a->rt, tmp); + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + return true; +} + +static bool trans_LDA(DisasContext *s, arg_LDA *a) +{ + return op_lda(s, a, MO_UL); +} + +static bool trans_LDAB(DisasContext *s, arg_LDA *a) +{ + return op_lda(s, a, MO_UB); +} + +static bool trans_LDAH(DisasContext *s, arg_LDA *a) +{ + return op_lda(s, a, MO_UW); +} + +/* + * Media instructions + */ + +static bool trans_USADA8(DisasContext *s, arg_USADA8 *a) +{ + TCGv_i32 t1, t2; + + if (!ENABLE_ARCH_6) { + return false; + } + + t1 = load_reg(s, a->rn); + t2 = load_reg(s, a->rm); + gen_helper_usad8(t1, t1, t2); + tcg_temp_free_i32(t2); + if (a->ra != 15) { + t2 = load_reg(s, a->ra); + tcg_gen_add_i32(t1, t1, t2); + tcg_temp_free_i32(t2); + } + store_reg(s, a->rd, t1); + return true; +} + +static bool op_bfx(DisasContext *s, arg_UBFX *a, bool u) +{ + TCGv_i32 tmp; + int width = a->widthm1 + 1; + int shift = a->lsb; + + if (!ENABLE_ARCH_6T2) { + return false; + } + if (shift + width > 32) { + /* UNPREDICTABLE; we choose to UNDEF */ + unallocated_encoding(s); + return true; + } + + tmp = load_reg(s, a->rn); + if (u) { + tcg_gen_extract_i32(tmp, tmp, shift, width); + } else { + tcg_gen_sextract_i32(tmp, tmp, shift, width); + } + store_reg(s, a->rd, tmp); + return true; +} + +static bool trans_SBFX(DisasContext *s, arg_SBFX *a) +{ + return op_bfx(s, a, false); +} + +static bool trans_UBFX(DisasContext *s, arg_UBFX *a) +{ + return op_bfx(s, a, true); +} + +static bool trans_BFCI(DisasContext *s, arg_BFCI *a) +{ + TCGv_i32 tmp; + int msb = a->msb, lsb = a->lsb; + int width; + + if (!ENABLE_ARCH_6T2) { + return false; + } + if (msb < lsb) { + /* UNPREDICTABLE; we choose to UNDEF */ + unallocated_encoding(s); + return true; + } + + width = msb + 1 - lsb; + if (a->rn == 15) { + /* BFC */ + tmp = tcg_const_i32(0); + } else { + /* BFI */ + tmp = load_reg(s, a->rn); + } + if (width != 32) { + TCGv_i32 tmp2 = load_reg(s, a->rd); + tcg_gen_deposit_i32(tmp, tmp2, tmp, lsb, width); + tcg_temp_free_i32(tmp2); + } + store_reg(s, a->rd, tmp); + return true; +} + +static bool trans_UDF(DisasContext *s, arg_UDF *a) +{ + unallocated_encoding(s); + return true; +} + +/* + * Parallel addition and subtraction + */ + +static bool op_par_addsub(DisasContext *s, arg_rrr *a, + void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32)) +{ + TCGv_i32 t0, t1; + + if (s->thumb + ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP) + : !ENABLE_ARCH_6) { + return false; + } + + t0 = load_reg(s, a->rn); + t1 = load_reg(s, a->rm); + + gen(t0, t0, t1); + + tcg_temp_free_i32(t1); + store_reg(s, a->rd, t0); + return true; +} + +static bool op_par_addsub_ge(DisasContext *s, arg_rrr *a, + void (*gen)(TCGv_i32, TCGv_i32, + TCGv_i32, TCGv_ptr)) +{ + TCGv_i32 t0, t1; + TCGv_ptr ge; + + if (s->thumb + ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP) + : !ENABLE_ARCH_6) { + return false; + } + + t0 = load_reg(s, a->rn); + t1 = load_reg(s, a->rm); + + ge = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(ge, cpu_env, offsetof(CPUARMState, GE)); + gen(t0, t0, t1, ge); + + tcg_temp_free_ptr(ge); + tcg_temp_free_i32(t1); + store_reg(s, a->rd, t0); + return true; +} + +#define DO_PAR_ADDSUB(NAME, helper) \ +static bool trans_##NAME(DisasContext *s, arg_rrr *a) \ +{ \ + return op_par_addsub(s, a, helper); \ +} + +#define DO_PAR_ADDSUB_GE(NAME, helper) \ +static bool trans_##NAME(DisasContext *s, arg_rrr *a) \ +{ \ + return op_par_addsub_ge(s, a, helper); \ +} + +DO_PAR_ADDSUB_GE(SADD16, gen_helper_sadd16) +DO_PAR_ADDSUB_GE(SASX, gen_helper_saddsubx) +DO_PAR_ADDSUB_GE(SSAX, gen_helper_ssubaddx) +DO_PAR_ADDSUB_GE(SSUB16, gen_helper_ssub16) +DO_PAR_ADDSUB_GE(SADD8, gen_helper_sadd8) +DO_PAR_ADDSUB_GE(SSUB8, gen_helper_ssub8) + +DO_PAR_ADDSUB_GE(UADD16, gen_helper_uadd16) +DO_PAR_ADDSUB_GE(UASX, gen_helper_uaddsubx) +DO_PAR_ADDSUB_GE(USAX, gen_helper_usubaddx) +DO_PAR_ADDSUB_GE(USUB16, gen_helper_usub16) +DO_PAR_ADDSUB_GE(UADD8, gen_helper_uadd8) +DO_PAR_ADDSUB_GE(USUB8, gen_helper_usub8) + +DO_PAR_ADDSUB(QADD16, gen_helper_qadd16) +DO_PAR_ADDSUB(QASX, gen_helper_qaddsubx) +DO_PAR_ADDSUB(QSAX, gen_helper_qsubaddx) +DO_PAR_ADDSUB(QSUB16, gen_helper_qsub16) +DO_PAR_ADDSUB(QADD8, gen_helper_qadd8) +DO_PAR_ADDSUB(QSUB8, gen_helper_qsub8) + +DO_PAR_ADDSUB(UQADD16, gen_helper_uqadd16) +DO_PAR_ADDSUB(UQASX, gen_helper_uqaddsubx) +DO_PAR_ADDSUB(UQSAX, gen_helper_uqsubaddx) +DO_PAR_ADDSUB(UQSUB16, gen_helper_uqsub16) +DO_PAR_ADDSUB(UQADD8, gen_helper_uqadd8) +DO_PAR_ADDSUB(UQSUB8, gen_helper_uqsub8) + +DO_PAR_ADDSUB(SHADD16, gen_helper_shadd16) +DO_PAR_ADDSUB(SHASX, gen_helper_shaddsubx) +DO_PAR_ADDSUB(SHSAX, gen_helper_shsubaddx) +DO_PAR_ADDSUB(SHSUB16, gen_helper_shsub16) +DO_PAR_ADDSUB(SHADD8, gen_helper_shadd8) +DO_PAR_ADDSUB(SHSUB8, gen_helper_shsub8) + +DO_PAR_ADDSUB(UHADD16, gen_helper_uhadd16) +DO_PAR_ADDSUB(UHASX, gen_helper_uhaddsubx) +DO_PAR_ADDSUB(UHSAX, gen_helper_uhsubaddx) +DO_PAR_ADDSUB(UHSUB16, gen_helper_uhsub16) +DO_PAR_ADDSUB(UHADD8, gen_helper_uhadd8) +DO_PAR_ADDSUB(UHSUB8, gen_helper_uhsub8) + +#undef DO_PAR_ADDSUB +#undef DO_PAR_ADDSUB_GE + +/* + * Packing, unpacking, saturation, and reversal + */ + +static bool trans_PKH(DisasContext *s, arg_PKH *a) +{ + TCGv_i32 tn, tm; + int shift = a->imm; + + if (s->thumb + ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP) + : !ENABLE_ARCH_6) { + return false; + } + + tn = load_reg(s, a->rn); + tm = load_reg(s, a->rm); + if (a->tb) { + /* PKHTB */ + if (shift == 0) { + shift = 31; + } + tcg_gen_sari_i32(tm, tm, shift); + tcg_gen_deposit_i32(tn, tn, tm, 0, 16); + } else { + /* PKHBT */ + tcg_gen_shli_i32(tm, tm, shift); + tcg_gen_deposit_i32(tn, tm, tn, 0, 16); + } + tcg_temp_free_i32(tm); + store_reg(s, a->rd, tn); + return true; +} + +static bool op_sat(DisasContext *s, arg_sat *a, + void (*gen)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) +{ + TCGv_i32 tmp, satimm; + int shift = a->imm; + + if (!ENABLE_ARCH_6) { + return false; + } + + tmp = load_reg(s, a->rn); + if (a->sh) { + tcg_gen_sari_i32(tmp, tmp, shift ? shift : 31); + } else { + tcg_gen_shli_i32(tmp, tmp, shift); + } + + satimm = tcg_const_i32(a->satimm); + gen(tmp, cpu_env, tmp, satimm); + tcg_temp_free_i32(satimm); + + store_reg(s, a->rd, tmp); + return true; +} + +static bool trans_SSAT(DisasContext *s, arg_sat *a) +{ + return op_sat(s, a, gen_helper_ssat); +} + +static bool trans_USAT(DisasContext *s, arg_sat *a) +{ + return op_sat(s, a, gen_helper_usat); +} + +static bool trans_SSAT16(DisasContext *s, arg_sat *a) +{ + if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + return false; + } + return op_sat(s, a, gen_helper_ssat16); +} + +static bool trans_USAT16(DisasContext *s, arg_sat *a) +{ + if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + return false; + } + return op_sat(s, a, gen_helper_usat16); +} + +static bool op_xta(DisasContext *s, arg_rrr_rot *a, + void (*gen_extract)(TCGv_i32, TCGv_i32), + void (*gen_add)(TCGv_i32, TCGv_i32, TCGv_i32)) +{ + TCGv_i32 tmp; + + if (!ENABLE_ARCH_6) { + return false; + } + + tmp = load_reg(s, a->rm); + /* + * TODO: In many cases we could do a shift instead of a rotate. + * Combined with a simple extend, that becomes an extract. + */ + tcg_gen_rotri_i32(tmp, tmp, a->rot * 8); + gen_extract(tmp, tmp); + + if (a->rn != 15) { + TCGv_i32 tmp2 = load_reg(s, a->rn); + gen_add(tmp, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + store_reg(s, a->rd, tmp); + return true; +} + +static bool trans_SXTAB(DisasContext *s, arg_rrr_rot *a) +{ + return op_xta(s, a, tcg_gen_ext8s_i32, tcg_gen_add_i32); +} + +static bool trans_SXTAH(DisasContext *s, arg_rrr_rot *a) +{ + return op_xta(s, a, tcg_gen_ext16s_i32, tcg_gen_add_i32); +} + +static bool trans_SXTAB16(DisasContext *s, arg_rrr_rot *a) +{ + if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + return false; + } + return op_xta(s, a, gen_helper_sxtb16, gen_add16); +} + +static bool trans_UXTAB(DisasContext *s, arg_rrr_rot *a) +{ + return op_xta(s, a, tcg_gen_ext8u_i32, tcg_gen_add_i32); +} + +static bool trans_UXTAH(DisasContext *s, arg_rrr_rot *a) +{ + return op_xta(s, a, tcg_gen_ext16u_i32, tcg_gen_add_i32); +} + +static bool trans_UXTAB16(DisasContext *s, arg_rrr_rot *a) +{ + if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + return false; + } + return op_xta(s, a, gen_helper_uxtb16, gen_add16); +} + +static bool trans_SEL(DisasContext *s, arg_rrr *a) +{ + TCGv_i32 t1, t2, t3; + + if (s->thumb + ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP) + : !ENABLE_ARCH_6) { + return false; + } + + t1 = load_reg(s, a->rn); + t2 = load_reg(s, a->rm); + t3 = tcg_temp_new_i32(); + tcg_gen_ld_i32(t3, cpu_env, offsetof(CPUARMState, GE)); + gen_helper_sel_flags(t1, t3, t1, t2); + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + store_reg(s, a->rd, t1); + return true; +} + +static bool op_rr(DisasContext *s, arg_rr *a, + void (*gen)(TCGv_i32, TCGv_i32)) +{ + TCGv_i32 tmp; + + tmp = load_reg(s, a->rm); + gen(tmp, tmp); + store_reg(s, a->rd, tmp); + return true; +} + +static bool trans_REV(DisasContext *s, arg_rr *a) +{ + if (!ENABLE_ARCH_6) { + return false; + } + return op_rr(s, a, tcg_gen_bswap32_i32); +} + +static bool trans_REV16(DisasContext *s, arg_rr *a) +{ + if (!ENABLE_ARCH_6) { + return false; + } + return op_rr(s, a, gen_rev16); +} + +static bool trans_REVSH(DisasContext *s, arg_rr *a) +{ + if (!ENABLE_ARCH_6) { + return false; + } + return op_rr(s, a, gen_revsh); +} + +static bool trans_RBIT(DisasContext *s, arg_rr *a) +{ + if (!ENABLE_ARCH_6T2) { + return false; + } + return op_rr(s, a, gen_helper_rbit); +} + +/* + * Signed multiply, signed and unsigned divide + */ + +static bool op_smlad(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub) +{ + TCGv_i32 t1, t2; + + if (!ENABLE_ARCH_6) { + return false; + } + + t1 = load_reg(s, a->rn); + t2 = load_reg(s, a->rm); + if (m_swap) { + gen_swap_half(t2); + } + gen_smul_dual(t1, t2); + + if (sub) { + /* This subtraction cannot overflow. */ + tcg_gen_sub_i32(t1, t1, t2); + } else { + /* + * This addition cannot overflow 32 bits; however it may + * overflow considered as a signed operation, in which case + * we must set the Q flag. + */ + gen_helper_add_setq(t1, cpu_env, t1, t2); + } + tcg_temp_free_i32(t2); + + if (a->ra != 15) { + t2 = load_reg(s, a->ra); + gen_helper_add_setq(t1, cpu_env, t1, t2); + tcg_temp_free_i32(t2); + } + store_reg(s, a->rd, t1); + return true; +} + +static bool trans_SMLAD(DisasContext *s, arg_rrrr *a) +{ + return op_smlad(s, a, false, false); +} + +static bool trans_SMLADX(DisasContext *s, arg_rrrr *a) +{ + return op_smlad(s, a, true, false); +} + +static bool trans_SMLSD(DisasContext *s, arg_rrrr *a) +{ + return op_smlad(s, a, false, true); +} + +static bool trans_SMLSDX(DisasContext *s, arg_rrrr *a) +{ + return op_smlad(s, a, true, true); +} + +static bool op_smlald(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub) +{ + TCGv_i32 t1, t2; + TCGv_i64 l1, l2; + + if (!ENABLE_ARCH_6) { + return false; + } + + t1 = load_reg(s, a->rn); + t2 = load_reg(s, a->rm); + if (m_swap) { + gen_swap_half(t2); + } + gen_smul_dual(t1, t2); + + l1 = tcg_temp_new_i64(); + l2 = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(l1, t1); + tcg_gen_ext_i32_i64(l2, t2); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + + if (sub) { + tcg_gen_sub_i64(l1, l1, l2); + } else { + tcg_gen_add_i64(l1, l1, l2); + } + tcg_temp_free_i64(l2); + + gen_addq(s, l1, a->ra, a->rd); + gen_storeq_reg(s, a->ra, a->rd, l1); + tcg_temp_free_i64(l1); + return true; +} + +static bool trans_SMLALD(DisasContext *s, arg_rrrr *a) +{ + return op_smlald(s, a, false, false); +} + +static bool trans_SMLALDX(DisasContext *s, arg_rrrr *a) +{ + return op_smlald(s, a, true, false); +} + +static bool trans_SMLSLD(DisasContext *s, arg_rrrr *a) +{ + return op_smlald(s, a, false, true); +} + +static bool trans_SMLSLDX(DisasContext *s, arg_rrrr *a) +{ + return op_smlald(s, a, true, true); +} + +static bool op_smmla(DisasContext *s, arg_rrrr *a, bool round, bool sub) +{ + TCGv_i32 t1, t2; + + if (s->thumb + ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP) + : !ENABLE_ARCH_6) { + return false; + } + + t1 = load_reg(s, a->rn); + t2 = load_reg(s, a->rm); + tcg_gen_muls2_i32(t2, t1, t1, t2); + + if (a->ra != 15) { + TCGv_i32 t3 = load_reg(s, a->ra); + if (sub) { + /* + * For SMMLS, we need a 64-bit subtract. Borrow caused by + * a non-zero multiplicand lowpart, and the correct result + * lowpart for rounding. + */ + TCGv_i32 zero = tcg_const_i32(0); + tcg_gen_sub2_i32(t2, t1, zero, t3, t2, t1); + tcg_temp_free_i32(zero); + } else { + tcg_gen_add_i32(t1, t1, t3); + } + tcg_temp_free_i32(t3); + } + if (round) { + /* + * Adding 0x80000000 to the 64-bit quantity means that we have + * carry in to the high word when the low word has the msb set. + */ + tcg_gen_shri_i32(t2, t2, 31); + tcg_gen_add_i32(t1, t1, t2); + } + tcg_temp_free_i32(t2); + store_reg(s, a->rd, t1); + return true; +} + +static bool trans_SMMLA(DisasContext *s, arg_rrrr *a) +{ + return op_smmla(s, a, false, false); +} + +static bool trans_SMMLAR(DisasContext *s, arg_rrrr *a) +{ + return op_smmla(s, a, true, false); +} + +static bool trans_SMMLS(DisasContext *s, arg_rrrr *a) +{ + return op_smmla(s, a, false, true); +} + +static bool trans_SMMLSR(DisasContext *s, arg_rrrr *a) +{ + return op_smmla(s, a, true, true); +} + +static bool op_div(DisasContext *s, arg_rrr *a, bool u) +{ + TCGv_i32 t1, t2; + + if (s->thumb + ? !dc_isar_feature(thumb_div, s) + : !dc_isar_feature(arm_div, s)) { + return false; + } + + t1 = load_reg(s, a->rn); + t2 = load_reg(s, a->rm); + if (u) { + gen_helper_udiv(t1, t1, t2); + } else { + gen_helper_sdiv(t1, t1, t2); + } + tcg_temp_free_i32(t2); + store_reg(s, a->rd, t1); + return true; +} + +static bool trans_SDIV(DisasContext *s, arg_rrr *a) +{ + return op_div(s, a, false); +} + +static bool trans_UDIV(DisasContext *s, arg_rrr *a) +{ + return op_div(s, a, true); +} + +/* + * Block data transfer + */ + +static TCGv_i32 op_addr_block_pre(DisasContext *s, arg_ldst_block *a, int n) +{ + TCGv_i32 addr = load_reg(s, a->rn); + + if (a->b) { + if (a->i) { + /* pre increment */ + tcg_gen_addi_i32(addr, addr, 4); + } else { + /* pre decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } + } else if (!a->i && n != 1) { + /* post decrement */ + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + + if (s->v8m_stackcheck && a->rn == 13 && a->w) { + /* + * If the writeback is incrementing SP rather than + * decrementing it, and the initial SP is below the + * stack limit but the final written-back SP would + * be above, then then we must not perform any memory + * accesses, but it is IMPDEF whether we generate + * an exception. We choose to do so in this case. + * At this point 'addr' is the lowest address, so + * either the original SP (if incrementing) or our + * final SP (if decrementing), so that's what we check. + */ + gen_helper_v8m_stackcheck(cpu_env, addr); + } + + return addr; +} + +static void op_addr_block_post(DisasContext *s, arg_ldst_block *a, + TCGv_i32 addr, int n) +{ + if (a->w) { + /* write back */ + if (!a->b) { + if (a->i) { + /* post increment */ + tcg_gen_addi_i32(addr, addr, 4); + } else { + /* post decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } + } else if (!a->i && n != 1) { + /* pre decrement */ + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + store_reg(s, a->rn, addr); + } else { + tcg_temp_free_i32(addr); + } +} + +static bool op_stm(DisasContext *s, arg_ldst_block *a, int min_n) +{ + int i, j, n, list, mem_idx; + bool user = a->u; + TCGv_i32 addr, tmp, tmp2; + + if (user) { + /* STM (user) */ + if (IS_USER(s)) { + /* Only usable in supervisor mode. */ + unallocated_encoding(s); + return true; + } + } + + list = a->list; + n = ctpop16(list); + if (n < min_n || a->rn == 15) { + unallocated_encoding(s); + return true; + } + + addr = op_addr_block_pre(s, a, n); + mem_idx = get_mem_index(s); + + for (i = j = 0; i < 16; i++) { + if (!(list & (1 << i))) { + continue; + } + + if (user && i != 15) { + tmp = tcg_temp_new_i32(); + tmp2 = tcg_const_i32(i); + gen_helper_get_user_reg(tmp, cpu_env, tmp2); + tcg_temp_free_i32(tmp2); + } else { + tmp = load_reg(s, i); + } + gen_aa32_st32(s, tmp, addr, mem_idx); + tcg_temp_free_i32(tmp); + + /* No need to add after the last transfer. */ + if (++j != n) { + tcg_gen_addi_i32(addr, addr, 4); + } + } + + op_addr_block_post(s, a, addr, n); + return true; +} + +static bool trans_STM(DisasContext *s, arg_ldst_block *a) +{ + /* BitCount(list) < 1 is UNPREDICTABLE */ + return op_stm(s, a, 1); +} + +static bool trans_STM_t32(DisasContext *s, arg_ldst_block *a) +{ + /* Writeback register in register list is UNPREDICTABLE for T32. */ + if (a->w && (a->list & (1 << a->rn))) { + unallocated_encoding(s); + return true; + } + /* BitCount(list) < 2 is UNPREDICTABLE */ + return op_stm(s, a, 2); +} + +static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) +{ + int i, j, n, list, mem_idx; + bool loaded_base; + bool user = a->u; + bool exc_return = false; + TCGv_i32 addr, tmp, tmp2, loaded_var; + + if (user) { + /* LDM (user), LDM (exception return) */ + if (IS_USER(s)) { + /* Only usable in supervisor mode. */ + unallocated_encoding(s); + return true; + } + if (extract32(a->list, 15, 1)) { + exc_return = true; + user = false; + } else { + /* LDM (user) does not allow writeback. */ + if (a->w) { + unallocated_encoding(s); + return true; + } + } + } + + list = a->list; + n = ctpop16(list); + if (n < min_n || a->rn == 15) { + unallocated_encoding(s); + return true; + } + + addr = op_addr_block_pre(s, a, n); + mem_idx = get_mem_index(s); + loaded_base = false; + loaded_var = NULL; + + for (i = j = 0; i < 16; i++) { + if (!(list & (1 << i))) { + continue; + } + + tmp = tcg_temp_new_i32(); + gen_aa32_ld32u(s, tmp, addr, mem_idx); + if (user) { + tmp2 = tcg_const_i32(i); + gen_helper_set_user_reg(cpu_env, tmp2, tmp); + tcg_temp_free_i32(tmp2); + tcg_temp_free_i32(tmp); + } else if (i == a->rn) { + loaded_var = tmp; + loaded_base = true; + } else if (i == 15 && exc_return) { + store_pc_exc_ret(s, tmp); + } else { + store_reg_from_load(s, i, tmp); + } + + /* No need to add after the last transfer. */ + if (++j != n) { + tcg_gen_addi_i32(addr, addr, 4); + } + } + + op_addr_block_post(s, a, addr, n); + + if (loaded_base) { + /* Note that we reject base == pc above. */ + store_reg(s, a->rn, loaded_var); + } + + if (exc_return) { + /* Restore CPSR from SPSR. */ + tmp = load_cpu_field(spsr); + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } + gen_helper_cpsr_write_eret(cpu_env, tmp); + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_io_end(); + } + tcg_temp_free_i32(tmp); + /* Must exit loop to check un-masked IRQs */ + s->base.is_jmp = DISAS_EXIT; + } + return true; +} + +static bool trans_LDM_a32(DisasContext *s, arg_ldst_block *a) +{ + /* + * Writeback register in register list is UNPREDICTABLE + * for ArchVersion() >= 7. Prior to v7, A32 would write + * an UNKNOWN value to the base register. + */ + if (ENABLE_ARCH_7 && a->w && (a->list & (1 << a->rn))) { + unallocated_encoding(s); + return true; + } + /* BitCount(list) < 1 is UNPREDICTABLE */ + return do_ldm(s, a, 1); +} + +static bool trans_LDM_t32(DisasContext *s, arg_ldst_block *a) +{ + /* Writeback register in register list is UNPREDICTABLE for T32. */ + if (a->w && (a->list & (1 << a->rn))) { + unallocated_encoding(s); + return true; + } + /* BitCount(list) < 2 is UNPREDICTABLE */ + return do_ldm(s, a, 2); +} + +static bool trans_LDM_t16(DisasContext *s, arg_ldst_block *a) +{ + /* Writeback is conditional on the base register not being loaded. */ + a->w = !(a->list & (1 << a->rn)); + /* BitCount(list) < 1 is UNPREDICTABLE */ + return do_ldm(s, a, 1); +} + +/* + * Branch, branch with link + */ + +static bool trans_B(DisasContext *s, arg_i *a) +{ + gen_jmp(s, read_pc(s) + a->imm); + return true; +} + +static bool trans_B_cond_thumb(DisasContext *s, arg_ci *a) +{ + /* This has cond from encoding, required to be outside IT block. */ + if (a->cond >= 0xe) { + return false; + } + if (s->condexec_mask) { + unallocated_encoding(s); + return true; + } + arm_skip_unless(s, a->cond); + gen_jmp(s, read_pc(s) + a->imm); + return true; +} + +static bool trans_BL(DisasContext *s, arg_i *a) +{ + tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb); + gen_jmp(s, read_pc(s) + a->imm); + return true; +} + +static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a) +{ + TCGv_i32 tmp; + + /* For A32, ARCH(5) is checked near the start of the uncond block. */ + if (s->thumb && (a->imm & 2)) { + return false; + } + tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb); + tmp = tcg_const_i32(!s->thumb); + store_cpu_field(tmp, thumb); + gen_jmp(s, (read_pc(s) & ~3) + a->imm); + return true; +} + +static bool trans_BL_BLX_prefix(DisasContext *s, arg_BL_BLX_prefix *a) +{ + assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2)); + tcg_gen_movi_i32(cpu_R[14], read_pc(s) + (a->imm << 12)); + return true; +} + +static bool trans_BL_suffix(DisasContext *s, arg_BL_suffix *a) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + + assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2)); + tcg_gen_addi_i32(tmp, cpu_R[14], (a->imm << 1) | 1); + tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1); + gen_bx(s, tmp); + return true; +} + +static bool trans_BLX_suffix(DisasContext *s, arg_BLX_suffix *a) +{ + TCGv_i32 tmp; + + assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2)); + if (!ENABLE_ARCH_5) { + return false; + } + tmp = tcg_temp_new_i32(); + tcg_gen_addi_i32(tmp, cpu_R[14], a->imm << 1); + tcg_gen_andi_i32(tmp, tmp, 0xfffffffc); + tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1); + gen_bx(s, tmp); + return true; +} + +static bool op_tbranch(DisasContext *s, arg_tbranch *a, bool half) +{ + TCGv_i32 addr, tmp; + + tmp = load_reg(s, a->rm); + if (half) { + tcg_gen_add_i32(tmp, tmp, tmp); + } + addr = load_reg(s, a->rn); + tcg_gen_add_i32(addr, addr, tmp); + + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), + half ? MO_UW | s->be_data : MO_UB); + tcg_temp_free_i32(addr); + + tcg_gen_add_i32(tmp, tmp, tmp); + tcg_gen_addi_i32(tmp, tmp, read_pc(s)); + store_reg(s, 15, tmp); + return true; +} + +static bool trans_TBB(DisasContext *s, arg_tbranch *a) +{ + return op_tbranch(s, a, false); +} + +static bool trans_TBH(DisasContext *s, arg_tbranch *a) +{ + return op_tbranch(s, a, true); +} + +static bool trans_CBZ(DisasContext *s, arg_CBZ *a) +{ + TCGv_i32 tmp = load_reg(s, a->rn); + + arm_gen_condlabel(s); + tcg_gen_brcondi_i32(a->nz ? TCG_COND_EQ : TCG_COND_NE, + tmp, 0, s->condlabel); + tcg_temp_free_i32(tmp); + gen_jmp(s, read_pc(s) + a->imm); + return true; +} + +/* + * Supervisor call + */ + +static bool trans_SVC(DisasContext *s, arg_SVC *a) +{ + gen_set_pc_im(s, s->base.pc_next); + s->svc_imm = a->imm; + s->base.is_jmp = DISAS_SWI; + return true; +} + +/* + * Unconditional system instructions + */ + +static bool trans_RFE(DisasContext *s, arg_RFE *a) +{ + static const int8_t pre_offset[4] = { + /* DA */ -4, /* IA */ 0, /* DB */ -8, /* IB */ 4 + }; + static const int8_t post_offset[4] = { + /* DA */ -8, /* IA */ 4, /* DB */ -4, /* IB */ 0 + }; + TCGv_i32 addr, t1, t2; + + if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + if (IS_USER(s)) { + unallocated_encoding(s); + return true; + } + + addr = load_reg(s, a->rn); + tcg_gen_addi_i32(addr, addr, pre_offset[a->pu]); + + /* Load PC into tmp and CPSR into tmp2. */ + t1 = tcg_temp_new_i32(); + gen_aa32_ld32u(s, t1, addr, get_mem_index(s)); + tcg_gen_addi_i32(addr, addr, 4); + t2 = tcg_temp_new_i32(); + gen_aa32_ld32u(s, t2, addr, get_mem_index(s)); + + if (a->w) { + /* Base writeback. */ + tcg_gen_addi_i32(addr, addr, post_offset[a->pu]); + store_reg(s, a->rn, addr); + } else { + tcg_temp_free_i32(addr); + } + gen_rfe(s, t1, t2); + return true; +} + +static bool trans_SRS(DisasContext *s, arg_SRS *a) +{ + if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + gen_srs(s, a->mode, a->pu, a->w); + return true; +} + +static bool trans_CPS(DisasContext *s, arg_CPS *a) +{ + uint32_t mask, val; + + if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + if (IS_USER(s)) { + /* Implemented as NOP in user mode. */ + return true; + } + /* TODO: There are quite a lot of UNPREDICTABLE argument combinations. */ + + mask = val = 0; + if (a->imod & 2) { + if (a->A) { + mask |= CPSR_A; + } + if (a->I) { + mask |= CPSR_I; + } + if (a->F) { + mask |= CPSR_F; + } + if (a->imod & 1) { + val |= mask; + } + } + if (a->M) { + mask |= CPSR_M; + val |= a->mode; + } + if (mask) { + gen_set_psr_im(s, mask, 0, val); + } + return true; +} + +static bool trans_CPS_v7m(DisasContext *s, arg_CPS_v7m *a) +{ + TCGv_i32 tmp, addr; + + if (!arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + if (IS_USER(s)) { + /* Implemented as NOP in user mode. */ + return true; + } + + tmp = tcg_const_i32(a->im); + /* FAULTMASK */ + if (a->F) { + addr = tcg_const_i32(19); + gen_helper_v7m_msr(cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + } + /* PRIMASK */ + if (a->I) { + addr = tcg_const_i32(16); + gen_helper_v7m_msr(cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + } + tcg_temp_free_i32(tmp); + gen_lookup_tb(s); + return true; +} + +/* + * Clear-Exclusive, Barriers + */ + +static bool trans_CLREX(DisasContext *s, arg_CLREX *a) +{ + if (s->thumb + ? !ENABLE_ARCH_7 && !arm_dc_feature(s, ARM_FEATURE_M) + : !ENABLE_ARCH_6K) { + return false; + } + gen_clrex(s); + return true; +} + +static bool trans_DSB(DisasContext *s, arg_DSB *a) +{ + if (!ENABLE_ARCH_7 && !arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); + return true; +} + +static bool trans_DMB(DisasContext *s, arg_DMB *a) +{ + return trans_DSB(s, NULL); +} + +static bool trans_ISB(DisasContext *s, arg_ISB *a) +{ + if (!ENABLE_ARCH_7 && !arm_dc_feature(s, ARM_FEATURE_M)) { + return false; + } + /* + * We need to break the TB after this insn to execute + * self-modifying code correctly and also to take + * any pending interrupts immediately. + */ + gen_goto_tb(s, 0, s->base.pc_next); + return true; +} + +static bool trans_SB(DisasContext *s, arg_SB *a) +{ + if (!dc_isar_feature(aa32_sb, s)) { + return false; + } + /* + * TODO: There is no speculation barrier opcode + * for TCG; MB and end the TB instead. + */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); + gen_goto_tb(s, 0, s->base.pc_next); + return true; +} + +static bool trans_SETEND(DisasContext *s, arg_SETEND *a) +{ + if (!ENABLE_ARCH_6) { + return false; + } + if (a->E != (s->be_data == MO_BE)) { + gen_helper_setend(cpu_env); + s->base.is_jmp = DISAS_UPDATE; + } + return true; +} + +/* + * Preload instructions + * All are nops, contingent on the appropriate arch level. + */ + +static bool trans_PLD(DisasContext *s, arg_PLD *a) +{ + return ENABLE_ARCH_5TE; +} + +static bool trans_PLDW(DisasContext *s, arg_PLD *a) +{ + return arm_dc_feature(s, ARM_FEATURE_V7MP); +} + +static bool trans_PLI(DisasContext *s, arg_PLD *a) +{ + return ENABLE_ARCH_7; +} + +/* + * If-then + */ + +static bool trans_IT(DisasContext *s, arg_IT *a) +{ + int cond_mask = a->cond_mask; + + /* + * No actual code generated for this insn, just setup state. + * + * Combinations of firstcond and mask which set up an 0b1111 + * condition are UNPREDICTABLE; we take the CONSTRAINED + * UNPREDICTABLE choice to treat 0b1111 the same as 0b1110, + * i.e. both meaning "execute always". + */ + s->condexec_cond = (cond_mask >> 4) & 0xe; + s->condexec_mask = cond_mask & 0x1f; + return true; +} + +/* + * Legacy decoder. + */ + +static void disas_arm_insn(DisasContext *s, unsigned int insn) +{ + unsigned int cond = insn >> 28; /* M variants do not implement ARM mode; this must raise the INVSTATE * UsageFault exception. @@ -7674,8 +10470,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) default_exception_el(s)); return; } - cond = insn >> 28; - if (cond == 0xf){ + + if (cond == 0xf) { /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we * choose to UNDEF. In ARMv5 and above the space is used * for miscellaneous unconditional instructions. @@ -7683,6 +10479,11 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) ARCH(5); /* Unconditional instructions. */ + if (disas_a32_uncond(s, insn)) { + return; + } + /* fall back to legacy decoder */ + if (((insn >> 25) & 7) == 1) { /* NEON Data processing. */ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { @@ -7712,133 +10513,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } return; } - if (((insn & 0x0f30f000) == 0x0510f000) || - ((insn & 0x0f30f010) == 0x0710f000)) { - if ((insn & (1 << 22)) == 0) { - /* PLDW; v7MP */ - if (!arm_dc_feature(s, ARM_FEATURE_V7MP)) { - goto illegal_op; - } - } - /* Otherwise PLD; v5TE+ */ - ARCH(5TE); - return; - } - if (((insn & 0x0f70f000) == 0x0450f000) || - ((insn & 0x0f70f010) == 0x0650f000)) { - ARCH(7); - return; /* PLI; V7 */ - } - if (((insn & 0x0f700000) == 0x04100000) || - ((insn & 0x0f700010) == 0x06100000)) { - if (!arm_dc_feature(s, ARM_FEATURE_V7MP)) { - goto illegal_op; - } - return; /* v7MP: Unallocated memory hint: must NOP */ - } - - if ((insn & 0x0ffffdff) == 0x01010000) { - ARCH(6); - /* setend */ - if (((insn >> 9) & 1) != !!(s->be_data == MO_BE)) { - gen_helper_setend(cpu_env); - s->base.is_jmp = DISAS_UPDATE; - } - return; - } else if ((insn & 0x0fffff00) == 0x057ff000) { - switch ((insn >> 4) & 0xf) { - case 1: /* clrex */ - ARCH(6K); - gen_clrex(s); - return; - case 4: /* dsb */ - case 5: /* dmb */ - ARCH(7); - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); - return; - case 6: /* isb */ - /* We need to break the TB after this insn to execute - * self-modifying code correctly and also to take - * any pending interrupts immediately. - */ - gen_goto_tb(s, 0, s->base.pc_next); - return; - case 7: /* sb */ - if ((insn & 0xf) || !dc_isar_feature(aa32_sb, s)) { - goto illegal_op; - } - /* - * TODO: There is no speculation barrier opcode - * for TCG; MB and end the TB instead. - */ - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); - gen_goto_tb(s, 0, s->base.pc_next); - return; - default: - goto illegal_op; - } - } else if ((insn & 0x0e5fffe0) == 0x084d0500) { - /* srs */ - ARCH(6); - gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21)); - return; - } else if ((insn & 0x0e50ffe0) == 0x08100a00) { - /* rfe */ - int32_t offset; - if (IS_USER(s)) - goto illegal_op; - ARCH(6); - rn = (insn >> 16) & 0xf; - addr = load_reg(s, rn); - i = (insn >> 23) & 3; - switch (i) { - case 0: offset = -4; break; /* DA */ - case 1: offset = 0; break; /* IA */ - case 2: offset = -8; break; /* DB */ - case 3: offset = 4; break; /* IB */ - default: abort(); - } - if (offset) - tcg_gen_addi_i32(addr, addr, offset); - /* Load PC into tmp and CPSR into tmp2. */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - tcg_gen_addi_i32(addr, addr, 4); - tmp2 = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s)); - if (insn & (1 << 21)) { - /* Base writeback. */ - switch (i) { - case 0: offset = -8; break; - case 1: offset = 4; break; - case 2: offset = -4; break; - case 3: offset = 0; break; - default: abort(); - } - if (offset) - tcg_gen_addi_i32(addr, addr, offset); - store_reg(s, rn, addr); - } else { - tcg_temp_free_i32(addr); - } - gen_rfe(s, tmp, tmp2); - return; - } else if ((insn & 0x0e000000) == 0x0a000000) { - /* branch link and change to thumb (blx <offset>) */ - int32_t offset; - - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, s->base.pc_next); - store_reg(s, 14, tmp); - /* Sign-extend the 24-bit offset */ - offset = (((int32_t)insn) << 8) >> 8; - val = read_pc(s); - /* offset * 4 + bit24 * 2 + (thumb bit) */ - val += (offset << 2) | ((insn >> 23) & 2) | 1; - /* protected by ARCH(5); above, near the start of uncond block */ - gen_bx_im(s, val); - return; - } else if ((insn & 0x0e000f00) == 0x0c000100) { + if ((insn & 0x0e000f00) == 0x0c000100) { if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) { /* iWMMXt register transfer. */ if (extract32(s->c15_cpar, 1, 1)) { @@ -7859,36 +10534,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) goto illegal_op; } return; - } else if ((insn & 0x0fe00000) == 0x0c400000) { - /* Coprocessor double register transfer. */ - ARCH(5TE); - } else if ((insn & 0x0f000010) == 0x0e000010) { - /* Additional coprocessor register transfer. */ - } else if ((insn & 0x0ff10020) == 0x01000000) { - uint32_t mask; - uint32_t val; - /* cps (privileged) */ - if (IS_USER(s)) - return; - mask = val = 0; - if (insn & (1 << 19)) { - if (insn & (1 << 8)) - mask |= CPSR_A; - if (insn & (1 << 7)) - mask |= CPSR_I; - if (insn & (1 << 6)) - mask |= CPSR_F; - if (insn & (1 << 18)) - val |= mask; - } - if (insn & (1 << 17)) { - mask |= CPSR_M; - val |= (insn & 0x1f); - } - if (mask) { - gen_set_psr_im(s, mask, 0, val); - } - return; } goto illegal_op; } @@ -7897,1313 +10542,30 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) next instruction */ arm_skip_unless(s, cond); } - if ((insn & 0x0f900000) == 0x03000000) { - if ((insn & (1 << 21)) == 0) { - ARCH(6T2); - rd = (insn >> 12) & 0xf; - val = ((insn >> 4) & 0xf000) | (insn & 0xfff); - if ((insn & (1 << 22)) == 0) { - /* MOVW */ - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, val); - } else { - /* MOVT */ - tmp = load_reg(s, rd); - tcg_gen_ext16u_i32(tmp, tmp); - tcg_gen_ori_i32(tmp, tmp, val << 16); - } - store_reg(s, rd, tmp); - } else { - if (((insn >> 12) & 0xf) != 0xf) - goto illegal_op; - if (((insn >> 16) & 0xf) == 0) { - gen_nop_hint(s, insn & 0xff); - } else { - /* CPSR = immediate */ - val = insn & 0xff; - shift = ((insn >> 8) & 0xf) * 2; - val = ror32(val, shift); - i = ((insn & (1 << 22)) != 0); - if (gen_set_psr_im(s, msr_mask(s, (insn >> 16) & 0xf, i), - i, val)) { - goto illegal_op; - } - } - } - } else if ((insn & 0x0f900000) == 0x01000000 - && (insn & 0x00000090) != 0x00000090) { - /* miscellaneous instructions */ - op1 = (insn >> 21) & 3; - sh = (insn >> 4) & 0xf; - rm = insn & 0xf; - switch (sh) { - case 0x0: /* MSR, MRS */ - if (insn & (1 << 9)) { - /* MSR (banked) and MRS (banked) */ - int sysm = extract32(insn, 16, 4) | - (extract32(insn, 8, 1) << 4); - int r = extract32(insn, 22, 1); - - if (op1 & 1) { - /* MSR (banked) */ - gen_msr_banked(s, r, sysm, rm); - } else { - /* MRS (banked) */ - int rd = extract32(insn, 12, 4); - - gen_mrs_banked(s, r, sysm, rd); - } - break; - } - - /* MSR, MRS (for PSRs) */ - if (op1 & 1) { - /* PSR = reg */ - tmp = load_reg(s, rm); - i = ((op1 & 2) != 0); - if (gen_set_psr(s, msr_mask(s, (insn >> 16) & 0xf, i), i, tmp)) - goto illegal_op; - } else { - /* reg = PSR */ - rd = (insn >> 12) & 0xf; - if (op1 & 2) { - if (IS_USER(s)) - goto illegal_op; - tmp = load_cpu_field(spsr); - } else { - tmp = tcg_temp_new_i32(); - gen_helper_cpsr_read(tmp, cpu_env); - } - store_reg(s, rd, tmp); - } - break; - case 0x1: - if (op1 == 1) { - /* branch/exchange thumb (bx). */ - ARCH(4T); - tmp = load_reg(s, rm); - gen_bx(s, tmp); - } else if (op1 == 3) { - /* clz */ - ARCH(5); - rd = (insn >> 12) & 0xf; - tmp = load_reg(s, rm); - tcg_gen_clzi_i32(tmp, tmp, 32); - store_reg(s, rd, tmp); - } else { - goto illegal_op; - } - break; - case 0x2: - if (op1 == 1) { - ARCH(5J); /* bxj */ - /* Trivial implementation equivalent to bx. */ - tmp = load_reg(s, rm); - gen_bx(s, tmp); - } else { - goto illegal_op; - } - break; - case 0x3: - if (op1 != 1) - goto illegal_op; - - ARCH(5); - /* branch link/exchange thumb (blx) */ - tmp = load_reg(s, rm); - tmp2 = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp2, s->base.pc_next); - store_reg(s, 14, tmp2); - gen_bx(s, tmp); - break; - case 0x4: - { - /* crc32/crc32c */ - uint32_t c = extract32(insn, 8, 4); - /* Check this CPU supports ARMv8 CRC instructions. - * op1 == 3 is UNPREDICTABLE but handle as UNDEFINED. - * Bits 8, 10 and 11 should be zero. - */ - if (!dc_isar_feature(aa32_crc32, s) || op1 == 0x3 || (c & 0xd) != 0) { - goto illegal_op; - } - - rn = extract32(insn, 16, 4); - rd = extract32(insn, 12, 4); + if (disas_a32(s, insn)) { + return; + } + /* fall back to legacy decoder */ - tmp = load_reg(s, rn); - tmp2 = load_reg(s, rm); - if (op1 == 0) { - tcg_gen_andi_i32(tmp2, tmp2, 0xff); - } else if (op1 == 1) { - tcg_gen_andi_i32(tmp2, tmp2, 0xffff); - } - tmp3 = tcg_const_i32(1 << op1); - if (c & 0x2) { - gen_helper_crc32c(tmp, tmp, tmp2, tmp3); - } else { - gen_helper_crc32(tmp, tmp, tmp2, tmp3); - } - tcg_temp_free_i32(tmp2); - tcg_temp_free_i32(tmp3); - store_reg(s, rd, tmp); - break; - } - case 0x5: /* saturating add/subtract */ - ARCH(5TE); - rd = (insn >> 12) & 0xf; - rn = (insn >> 16) & 0xf; - tmp = load_reg(s, rm); - tmp2 = load_reg(s, rn); - if (op1 & 2) - gen_helper_add_saturate(tmp2, cpu_env, tmp2, tmp2); - if (op1 & 1) - gen_helper_sub_saturate(tmp, cpu_env, tmp, tmp2); - else - gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2); - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - break; - case 0x6: /* ERET */ - if (op1 != 3) { - goto illegal_op; - } - if (!arm_dc_feature(s, ARM_FEATURE_V7VE)) { - goto illegal_op; - } - if ((insn & 0x000fff0f) != 0x0000000e) { - /* UNPREDICTABLE; we choose to UNDEF */ + switch ((insn >> 24) & 0xf) { + case 0xc: + case 0xd: + case 0xe: + if (((insn >> 8) & 0xe) == 10) { + /* VFP. */ + if (disas_vfp_insn(s, insn)) { goto illegal_op; } - - if (s->current_el == 2) { - tmp = load_cpu_field(elr_el[2]); - } else { - tmp = load_reg(s, 14); - } - gen_exception_return(s, tmp); - break; - case 7: - { - int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4); - switch (op1) { - case 0: - /* HLT */ - gen_hlt(s, imm16); - break; - case 1: - /* bkpt */ - ARCH(5); - gen_exception_bkpt_insn(s, syn_aa32_bkpt(imm16, false)); - break; - case 2: - /* Hypervisor call (v7) */ - ARCH(7); - if (IS_USER(s)) { - goto illegal_op; - } - gen_hvc(s, imm16); - break; - case 3: - /* Secure monitor call (v6+) */ - ARCH(6K); - if (IS_USER(s)) { - goto illegal_op; - } - gen_smc(s); - break; - default: - g_assert_not_reached(); - } - break; - } - case 0x8: /* signed multiply */ - case 0xa: - case 0xc: - case 0xe: - ARCH(5TE); - rs = (insn >> 8) & 0xf; - rn = (insn >> 12) & 0xf; - rd = (insn >> 16) & 0xf; - if (op1 == 1) { - /* (32 * 16) >> 16 */ - tmp = load_reg(s, rm); - tmp2 = load_reg(s, rs); - if (sh & 4) - tcg_gen_sari_i32(tmp2, tmp2, 16); - else - gen_sxth(tmp2); - tmp64 = gen_muls_i64_i32(tmp, tmp2); - tcg_gen_shri_i64(tmp64, tmp64, 16); - tmp = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(tmp, tmp64); - tcg_temp_free_i64(tmp64); - if ((sh & 2) == 0) { - tmp2 = load_reg(s, rn); - gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - store_reg(s, rd, tmp); - } else { - /* 16 * 16 */ - tmp = load_reg(s, rm); - tmp2 = load_reg(s, rs); - gen_mulxy(tmp, tmp2, sh & 2, sh & 4); - tcg_temp_free_i32(tmp2); - if (op1 == 2) { - tmp64 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp64, tmp); - tcg_temp_free_i32(tmp); - gen_addq(s, tmp64, rn, rd); - gen_storeq_reg(s, rn, rd, tmp64); - tcg_temp_free_i64(tmp64); - } else { - if (op1 == 0) { - tmp2 = load_reg(s, rn); - gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - store_reg(s, rd, tmp); - } - } - break; - default: + } else if (disas_coproc_insn(s, insn)) { + /* Coprocessor. */ goto illegal_op; } - } else if (((insn & 0x0e000000) == 0 && - (insn & 0x00000090) != 0x90) || - ((insn & 0x0e000000) == (1 << 25))) { - int set_cc, logic_cc, shiftop; - - op1 = (insn >> 21) & 0xf; - set_cc = (insn >> 20) & 1; - logic_cc = table_logic_cc[op1] & set_cc; - - /* data processing instruction */ - if (insn & (1 << 25)) { - /* immediate operand */ - val = insn & 0xff; - shift = ((insn >> 8) & 0xf) * 2; - val = ror32(val, shift); - tmp2 = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp2, val); - if (logic_cc && shift) { - gen_set_CF_bit31(tmp2); - } - } else { - /* register */ - rm = (insn) & 0xf; - tmp2 = load_reg(s, rm); - shiftop = (insn >> 5) & 3; - if (!(insn & (1 << 4))) { - shift = (insn >> 7) & 0x1f; - gen_arm_shift_im(tmp2, shiftop, shift, logic_cc); - } else { - rs = (insn >> 8) & 0xf; - tmp = load_reg(s, rs); - gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc); - } - } - if (op1 != 0x0f && op1 != 0x0d) { - rn = (insn >> 16) & 0xf; - tmp = load_reg(s, rn); - } else { - tmp = NULL; - } - rd = (insn >> 12) & 0xf; - switch(op1) { - case 0x00: - tcg_gen_and_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, rd, tmp); - break; - case 0x01: - tcg_gen_xor_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, rd, tmp); - break; - case 0x02: - if (set_cc && rd == 15) { - /* SUBS r15, ... is used for exception return. */ - if (IS_USER(s)) { - goto illegal_op; - } - gen_sub_CC(tmp, tmp, tmp2); - gen_exception_return(s, tmp); - } else { - if (set_cc) { - gen_sub_CC(tmp, tmp, tmp2); - } else { - tcg_gen_sub_i32(tmp, tmp, tmp2); - } - store_reg_bx(s, rd, tmp); - } - break; - case 0x03: - if (set_cc) { - gen_sub_CC(tmp, tmp2, tmp); - } else { - tcg_gen_sub_i32(tmp, tmp2, tmp); - } - store_reg_bx(s, rd, tmp); - break; - case 0x04: - if (set_cc) { - gen_add_CC(tmp, tmp, tmp2); - } else { - tcg_gen_add_i32(tmp, tmp, tmp2); - } - store_reg_bx(s, rd, tmp); - break; - case 0x05: - if (set_cc) { - gen_adc_CC(tmp, tmp, tmp2); - } else { - gen_add_carry(tmp, tmp, tmp2); - } - store_reg_bx(s, rd, tmp); - break; - case 0x06: - if (set_cc) { - gen_sbc_CC(tmp, tmp, tmp2); - } else { - gen_sub_carry(tmp, tmp, tmp2); - } - store_reg_bx(s, rd, tmp); - break; - case 0x07: - if (set_cc) { - gen_sbc_CC(tmp, tmp2, tmp); - } else { - gen_sub_carry(tmp, tmp2, tmp); - } - store_reg_bx(s, rd, tmp); - break; - case 0x08: - if (set_cc) { - tcg_gen_and_i32(tmp, tmp, tmp2); - gen_logic_CC(tmp); - } - tcg_temp_free_i32(tmp); - break; - case 0x09: - if (set_cc) { - tcg_gen_xor_i32(tmp, tmp, tmp2); - gen_logic_CC(tmp); - } - tcg_temp_free_i32(tmp); - break; - case 0x0a: - if (set_cc) { - gen_sub_CC(tmp, tmp, tmp2); - } - tcg_temp_free_i32(tmp); - break; - case 0x0b: - if (set_cc) { - gen_add_CC(tmp, tmp, tmp2); - } - tcg_temp_free_i32(tmp); - break; - case 0x0c: - tcg_gen_or_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, rd, tmp); - break; - case 0x0d: - if (logic_cc && rd == 15) { - /* MOVS r15, ... is used for exception return. */ - if (IS_USER(s)) { - goto illegal_op; - } - gen_exception_return(s, tmp2); - } else { - if (logic_cc) { - gen_logic_CC(tmp2); - } - store_reg_bx(s, rd, tmp2); - } - break; - case 0x0e: - tcg_gen_andc_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, rd, tmp); - break; - default: - case 0x0f: - tcg_gen_not_i32(tmp2, tmp2); - if (logic_cc) { - gen_logic_CC(tmp2); - } - store_reg_bx(s, rd, tmp2); - break; - } - if (op1 != 0x0f && op1 != 0x0d) { - tcg_temp_free_i32(tmp2); - } - } else { - /* other instructions */ - op1 = (insn >> 24) & 0xf; - switch(op1) { - case 0x0: - case 0x1: - /* multiplies, extra load/stores */ - sh = (insn >> 5) & 3; - if (sh == 0) { - if (op1 == 0x0) { - rd = (insn >> 16) & 0xf; - rn = (insn >> 12) & 0xf; - rs = (insn >> 8) & 0xf; - rm = (insn) & 0xf; - op1 = (insn >> 20) & 0xf; - switch (op1) { - case 0: case 1: case 2: case 3: case 6: - /* 32 bit mul */ - tmp = load_reg(s, rs); - tmp2 = load_reg(s, rm); - tcg_gen_mul_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - if (insn & (1 << 22)) { - /* Subtract (mls) */ - ARCH(6T2); - tmp2 = load_reg(s, rn); - tcg_gen_sub_i32(tmp, tmp2, tmp); - tcg_temp_free_i32(tmp2); - } else if (insn & (1 << 21)) { - /* Add */ - tmp2 = load_reg(s, rn); - tcg_gen_add_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - if (insn & (1 << 20)) - gen_logic_CC(tmp); - store_reg(s, rd, tmp); - break; - case 4: - /* 64 bit mul double accumulate (UMAAL) */ - ARCH(6); - tmp = load_reg(s, rs); - tmp2 = load_reg(s, rm); - tmp64 = gen_mulu_i64_i32(tmp, tmp2); - gen_addq_lo(s, tmp64, rn); - gen_addq_lo(s, tmp64, rd); - gen_storeq_reg(s, rn, rd, tmp64); - tcg_temp_free_i64(tmp64); - break; - case 8: case 9: case 10: case 11: - case 12: case 13: case 14: case 15: - /* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */ - tmp = load_reg(s, rs); - tmp2 = load_reg(s, rm); - if (insn & (1 << 22)) { - tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2); - } else { - tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2); - } - if (insn & (1 << 21)) { /* mult accumulate */ - TCGv_i32 al = load_reg(s, rn); - TCGv_i32 ah = load_reg(s, rd); - tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, al, ah); - tcg_temp_free_i32(al); - tcg_temp_free_i32(ah); - } - if (insn & (1 << 20)) { - gen_logicq_cc(tmp, tmp2); - } - store_reg(s, rn, tmp); - store_reg(s, rd, tmp2); - break; - default: - goto illegal_op; - } - } else { - rn = (insn >> 16) & 0xf; - rd = (insn >> 12) & 0xf; - if (insn & (1 << 23)) { - /* load/store exclusive */ - bool is_ld = extract32(insn, 20, 1); - bool is_lasr = !extract32(insn, 8, 1); - int op2 = (insn >> 8) & 3; - op1 = (insn >> 21) & 0x3; - - switch (op2) { - case 0: /* lda/stl */ - if (op1 == 1) { - goto illegal_op; - } - ARCH(8); - break; - case 1: /* reserved */ - goto illegal_op; - case 2: /* ldaex/stlex */ - ARCH(8); - break; - case 3: /* ldrex/strex */ - if (op1) { - ARCH(6K); - } else { - ARCH(6); - } - break; - } - - addr = tcg_temp_local_new_i32(); - load_reg_var(s, addr, rn); - - if (is_lasr && !is_ld) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); - } - - if (op2 == 0) { - if (is_ld) { - tmp = tcg_temp_new_i32(); - switch (op1) { - case 0: /* lda */ - gen_aa32_ld32u_iss(s, tmp, addr, - get_mem_index(s), - rd | ISSIsAcqRel); - break; - case 2: /* ldab */ - gen_aa32_ld8u_iss(s, tmp, addr, - get_mem_index(s), - rd | ISSIsAcqRel); - break; - case 3: /* ldah */ - gen_aa32_ld16u_iss(s, tmp, addr, - get_mem_index(s), - rd | ISSIsAcqRel); - break; - default: - abort(); - } - store_reg(s, rd, tmp); - } else { - rm = insn & 0xf; - tmp = load_reg(s, rm); - switch (op1) { - case 0: /* stl */ - gen_aa32_st32_iss(s, tmp, addr, - get_mem_index(s), - rm | ISSIsAcqRel); - break; - case 2: /* stlb */ - gen_aa32_st8_iss(s, tmp, addr, - get_mem_index(s), - rm | ISSIsAcqRel); - break; - case 3: /* stlh */ - gen_aa32_st16_iss(s, tmp, addr, - get_mem_index(s), - rm | ISSIsAcqRel); - break; - default: - abort(); - } - tcg_temp_free_i32(tmp); - } - } else if (is_ld) { - switch (op1) { - case 0: /* ldrex */ - gen_load_exclusive(s, rd, 15, addr, 2); - break; - case 1: /* ldrexd */ - gen_load_exclusive(s, rd, rd + 1, addr, 3); - break; - case 2: /* ldrexb */ - gen_load_exclusive(s, rd, 15, addr, 0); - break; - case 3: /* ldrexh */ - gen_load_exclusive(s, rd, 15, addr, 1); - break; - default: - abort(); - } - } else { - rm = insn & 0xf; - switch (op1) { - case 0: /* strex */ - gen_store_exclusive(s, rd, rm, 15, addr, 2); - break; - case 1: /* strexd */ - gen_store_exclusive(s, rd, rm, rm + 1, addr, 3); - break; - case 2: /* strexb */ - gen_store_exclusive(s, rd, rm, 15, addr, 0); - break; - case 3: /* strexh */ - gen_store_exclusive(s, rd, rm, 15, addr, 1); - break; - default: - abort(); - } - } - tcg_temp_free_i32(addr); - - if (is_lasr && is_ld) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); - } - } else if ((insn & 0x00300f00) == 0) { - /* 0bcccc_0001_0x00_xxxx_xxxx_0000_1001_xxxx - * - SWP, SWPB - */ - - TCGv taddr; - TCGMemOp opc = s->be_data; - - rm = (insn) & 0xf; - - if (insn & (1 << 22)) { - opc |= MO_UB; - } else { - opc |= MO_UL | MO_ALIGN; - } - - addr = load_reg(s, rn); - taddr = gen_aa32_addr(s, addr, opc); - tcg_temp_free_i32(addr); - - tmp = load_reg(s, rm); - tcg_gen_atomic_xchg_i32(tmp, taddr, tmp, - get_mem_index(s), opc); - tcg_temp_free(taddr); - store_reg(s, rd, tmp); - } else { - goto illegal_op; - } - } - } else { - int address_offset; - bool load = insn & (1 << 20); - bool wbit = insn & (1 << 21); - bool pbit = insn & (1 << 24); - bool doubleword = false; - ISSInfo issinfo; - - /* Misc load/store */ - rn = (insn >> 16) & 0xf; - rd = (insn >> 12) & 0xf; - - /* ISS not valid if writeback */ - issinfo = (pbit & !wbit) ? rd : ISSInvalid; - - if (!load && (sh & 2)) { - /* doubleword */ - ARCH(5TE); - if (rd & 1) { - /* UNPREDICTABLE; we choose to UNDEF */ - goto illegal_op; - } - load = (sh & 1) == 0; - doubleword = true; - } - - addr = load_reg(s, rn); - if (pbit) { - gen_add_datah_offset(s, insn, 0, addr); - } - address_offset = 0; - - if (doubleword) { - if (!load) { - /* store */ - tmp = load_reg(s, rd); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp); - tcg_gen_addi_i32(addr, addr, 4); - tmp = load_reg(s, rd + 1); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp); - } else { - /* load */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - store_reg(s, rd, tmp); - tcg_gen_addi_i32(addr, addr, 4); - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - rd++; - } - address_offset = -4; - } else if (load) { - /* load */ - tmp = tcg_temp_new_i32(); - switch (sh) { - case 1: - gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), - issinfo); - break; - case 2: - gen_aa32_ld8s_iss(s, tmp, addr, get_mem_index(s), - issinfo); - break; - default: - case 3: - gen_aa32_ld16s_iss(s, tmp, addr, get_mem_index(s), - issinfo); - break; - } - } else { - /* store */ - tmp = load_reg(s, rd); - gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), issinfo); - tcg_temp_free_i32(tmp); - } - /* Perform base writeback before the loaded value to - ensure correct behavior with overlapping index registers. - ldrd with base writeback is undefined if the - destination and index registers overlap. */ - if (!pbit) { - gen_add_datah_offset(s, insn, address_offset, addr); - store_reg(s, rn, addr); - } else if (wbit) { - if (address_offset) - tcg_gen_addi_i32(addr, addr, address_offset); - store_reg(s, rn, addr); - } else { - tcg_temp_free_i32(addr); - } - if (load) { - /* Complete the load. */ - store_reg(s, rd, tmp); - } - } - break; - case 0x4: - case 0x5: - goto do_ldst; - case 0x6: - case 0x7: - if (insn & (1 << 4)) { - ARCH(6); - /* Armv6 Media instructions. */ - rm = insn & 0xf; - rn = (insn >> 16) & 0xf; - rd = (insn >> 12) & 0xf; - rs = (insn >> 8) & 0xf; - switch ((insn >> 23) & 3) { - case 0: /* Parallel add/subtract. */ - op1 = (insn >> 20) & 7; - tmp = load_reg(s, rn); - tmp2 = load_reg(s, rm); - sh = (insn >> 5) & 7; - if ((op1 & 3) == 0 || sh == 5 || sh == 6) - goto illegal_op; - gen_arm_parallel_addsub(op1, sh, tmp, tmp2); - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - break; - case 1: - if ((insn & 0x00700020) == 0) { - /* Halfword pack. */ - tmp = load_reg(s, rn); - tmp2 = load_reg(s, rm); - shift = (insn >> 7) & 0x1f; - if (insn & (1 << 6)) { - /* pkhtb */ - if (shift == 0) { - shift = 31; - } - tcg_gen_sari_i32(tmp2, tmp2, shift); - tcg_gen_deposit_i32(tmp, tmp, tmp2, 0, 16); - } else { - /* pkhbt */ - tcg_gen_shli_i32(tmp2, tmp2, shift); - tcg_gen_deposit_i32(tmp, tmp2, tmp, 0, 16); - } - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - } else if ((insn & 0x00200020) == 0x00200000) { - /* [us]sat */ - tmp = load_reg(s, rm); - shift = (insn >> 7) & 0x1f; - if (insn & (1 << 6)) { - if (shift == 0) - shift = 31; - tcg_gen_sari_i32(tmp, tmp, shift); - } else { - tcg_gen_shli_i32(tmp, tmp, shift); - } - sh = (insn >> 16) & 0x1f; - tmp2 = tcg_const_i32(sh); - if (insn & (1 << 22)) - gen_helper_usat(tmp, cpu_env, tmp, tmp2); - else - gen_helper_ssat(tmp, cpu_env, tmp, tmp2); - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - } else if ((insn & 0x00300fe0) == 0x00200f20) { - /* [us]sat16 */ - tmp = load_reg(s, rm); - sh = (insn >> 16) & 0x1f; - tmp2 = tcg_const_i32(sh); - if (insn & (1 << 22)) - gen_helper_usat16(tmp, cpu_env, tmp, tmp2); - else - gen_helper_ssat16(tmp, cpu_env, tmp, tmp2); - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - } else if ((insn & 0x00700fe0) == 0x00000fa0) { - /* Select bytes. */ - tmp = load_reg(s, rn); - tmp2 = load_reg(s, rm); - tmp3 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE)); - gen_helper_sel_flags(tmp, tmp3, tmp, tmp2); - tcg_temp_free_i32(tmp3); - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - } else if ((insn & 0x000003e0) == 0x00000060) { - tmp = load_reg(s, rm); - shift = (insn >> 10) & 3; - /* ??? In many cases it's not necessary to do a - rotate, a shift is sufficient. */ - tcg_gen_rotri_i32(tmp, tmp, shift * 8); - op1 = (insn >> 20) & 7; - switch (op1) { - case 0: gen_sxtb16(tmp); break; - case 2: gen_sxtb(tmp); break; - case 3: gen_sxth(tmp); break; - case 4: gen_uxtb16(tmp); break; - case 6: gen_uxtb(tmp); break; - case 7: gen_uxth(tmp); break; - default: goto illegal_op; - } - if (rn != 15) { - tmp2 = load_reg(s, rn); - if ((op1 & 3) == 0) { - gen_add16(tmp, tmp2); - } else { - tcg_gen_add_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - } - store_reg(s, rd, tmp); - } else if ((insn & 0x003f0f60) == 0x003f0f20) { - /* rev */ - tmp = load_reg(s, rm); - if (insn & (1 << 22)) { - if (insn & (1 << 7)) { - gen_revsh(tmp); - } else { - ARCH(6T2); - gen_helper_rbit(tmp, tmp); - } - } else { - if (insn & (1 << 7)) - gen_rev16(tmp); - else - tcg_gen_bswap32_i32(tmp, tmp); - } - store_reg(s, rd, tmp); - } else { - goto illegal_op; - } - break; - case 2: /* Multiplies (Type 3). */ - switch ((insn >> 20) & 0x7) { - case 5: - if (((insn >> 6) ^ (insn >> 7)) & 1) { - /* op2 not 00x or 11x : UNDEF */ - goto illegal_op; - } - /* Signed multiply most significant [accumulate]. - (SMMUL, SMMLA, SMMLS) */ - tmp = load_reg(s, rm); - tmp2 = load_reg(s, rs); - tcg_gen_muls2_i32(tmp2, tmp, tmp, tmp2); - - if (rd != 15) { - tmp3 = load_reg(s, rd); - if (insn & (1 << 6)) { - tcg_gen_sub_i32(tmp, tmp, tmp3); - } else { - tcg_gen_add_i32(tmp, tmp, tmp3); - } - tcg_temp_free_i32(tmp3); - } - if (insn & (1 << 5)) { - /* - * Adding 0x80000000 to the 64-bit quantity - * means that we have carry in to the high - * word when the low word has the high bit set. - */ - tcg_gen_shri_i32(tmp2, tmp2, 31); - tcg_gen_add_i32(tmp, tmp, tmp2); - } - tcg_temp_free_i32(tmp2); - store_reg(s, rn, tmp); - break; - case 0: - case 4: - /* SMLAD, SMUAD, SMLSD, SMUSD, SMLALD, SMLSLD */ - if (insn & (1 << 7)) { - goto illegal_op; - } - tmp = load_reg(s, rm); - tmp2 = load_reg(s, rs); - if (insn & (1 << 5)) - gen_swap_half(tmp2); - gen_smul_dual(tmp, tmp2); - if (insn & (1 << 22)) { - /* smlald, smlsld */ - TCGv_i64 tmp64_2; - - tmp64 = tcg_temp_new_i64(); - tmp64_2 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp64, tmp); - tcg_gen_ext_i32_i64(tmp64_2, tmp2); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - if (insn & (1 << 6)) { - tcg_gen_sub_i64(tmp64, tmp64, tmp64_2); - } else { - tcg_gen_add_i64(tmp64, tmp64, tmp64_2); - } - tcg_temp_free_i64(tmp64_2); - gen_addq(s, tmp64, rd, rn); - gen_storeq_reg(s, rd, rn, tmp64); - tcg_temp_free_i64(tmp64); - } else { - /* smuad, smusd, smlad, smlsd */ - if (insn & (1 << 6)) { - /* This subtraction cannot overflow. */ - tcg_gen_sub_i32(tmp, tmp, tmp2); - } else { - /* This addition cannot overflow 32 bits; - * however it may overflow considered as a - * signed operation, in which case we must set - * the Q flag. - */ - gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); - } - tcg_temp_free_i32(tmp2); - if (rd != 15) - { - tmp2 = load_reg(s, rd); - gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - store_reg(s, rn, tmp); - } - break; - case 1: - case 3: - /* SDIV, UDIV */ - if (!dc_isar_feature(arm_div, s)) { - goto illegal_op; - } - if (((insn >> 5) & 7) || (rd != 15)) { - goto illegal_op; - } - tmp = load_reg(s, rm); - tmp2 = load_reg(s, rs); - if (insn & (1 << 21)) { - gen_helper_udiv(tmp, tmp, tmp2); - } else { - gen_helper_sdiv(tmp, tmp, tmp2); - } - tcg_temp_free_i32(tmp2); - store_reg(s, rn, tmp); - break; - default: - goto illegal_op; - } - break; - case 3: - op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7); - switch (op1) { - case 0: /* Unsigned sum of absolute differences. */ - ARCH(6); - tmp = load_reg(s, rm); - tmp2 = load_reg(s, rs); - gen_helper_usad8(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - if (rd != 15) { - tmp2 = load_reg(s, rd); - tcg_gen_add_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - store_reg(s, rn, tmp); - break; - case 0x20: case 0x24: case 0x28: case 0x2c: - /* Bitfield insert/clear. */ - ARCH(6T2); - shift = (insn >> 7) & 0x1f; - i = (insn >> 16) & 0x1f; - if (i < shift) { - /* UNPREDICTABLE; we choose to UNDEF */ - goto illegal_op; - } - i = i + 1 - shift; - if (rm == 15) { - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, 0); - } else { - tmp = load_reg(s, rm); - } - if (i != 32) { - tmp2 = load_reg(s, rd); - tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, i); - tcg_temp_free_i32(tmp2); - } - store_reg(s, rd, tmp); - break; - case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */ - case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */ - ARCH(6T2); - tmp = load_reg(s, rm); - shift = (insn >> 7) & 0x1f; - i = ((insn >> 16) & 0x1f) + 1; - if (shift + i > 32) - goto illegal_op; - if (i < 32) { - if (op1 & 0x20) { - tcg_gen_extract_i32(tmp, tmp, shift, i); - } else { - tcg_gen_sextract_i32(tmp, tmp, shift, i); - } - } - store_reg(s, rd, tmp); - break; - default: - goto illegal_op; - } - break; - } - break; - } - do_ldst: - /* Check for undefined extension instructions - * per the ARM Bible IE: - * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx - */ - sh = (0xf << 20) | (0xf << 4); - if (op1 == 0x7 && ((insn & sh) == sh)) - { - goto illegal_op; - } - /* load/store byte/word */ - rn = (insn >> 16) & 0xf; - rd = (insn >> 12) & 0xf; - tmp2 = load_reg(s, rn); - if ((insn & 0x01200000) == 0x00200000) { - /* ldrt/strt */ - i = get_a32_user_mem_index(s); - } else { - i = get_mem_index(s); - } - if (insn & (1 << 24)) - gen_add_data_offset(s, insn, tmp2); - if (insn & (1 << 20)) { - /* load */ - tmp = tcg_temp_new_i32(); - if (insn & (1 << 22)) { - gen_aa32_ld8u_iss(s, tmp, tmp2, i, rd); - } else { - gen_aa32_ld32u_iss(s, tmp, tmp2, i, rd); - } - } else { - /* store */ - tmp = load_reg(s, rd); - if (insn & (1 << 22)) { - gen_aa32_st8_iss(s, tmp, tmp2, i, rd); - } else { - gen_aa32_st32_iss(s, tmp, tmp2, i, rd); - } - tcg_temp_free_i32(tmp); - } - if (!(insn & (1 << 24))) { - gen_add_data_offset(s, insn, tmp2); - store_reg(s, rn, tmp2); - } else if (insn & (1 << 21)) { - store_reg(s, rn, tmp2); - } else { - tcg_temp_free_i32(tmp2); - } - if (insn & (1 << 20)) { - /* Complete the load. */ - store_reg_from_load(s, rd, tmp); - } - break; - case 0x08: - case 0x09: - { - int j, n, loaded_base; - bool exc_return = false; - bool is_load = extract32(insn, 20, 1); - bool user = false; - TCGv_i32 loaded_var; - /* load/store multiple words */ - /* XXX: store correct base if write back */ - if (insn & (1 << 22)) { - /* LDM (user), LDM (exception return) and STM (user) */ - if (IS_USER(s)) - goto illegal_op; /* only usable in supervisor mode */ - - if (is_load && extract32(insn, 15, 1)) { - exc_return = true; - } else { - user = true; - } - } - rn = (insn >> 16) & 0xf; - addr = load_reg(s, rn); - - /* compute total size */ - loaded_base = 0; - loaded_var = NULL; - n = 0; - for (i = 0; i < 16; i++) { - if (insn & (1 << i)) - n++; - } - /* XXX: test invalid n == 0 case ? */ - if (insn & (1 << 23)) { - if (insn & (1 << 24)) { - /* pre increment */ - tcg_gen_addi_i32(addr, addr, 4); - } else { - /* post increment */ - } - } else { - if (insn & (1 << 24)) { - /* pre decrement */ - tcg_gen_addi_i32(addr, addr, -(n * 4)); - } else { - /* post decrement */ - if (n != 1) - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); - } - } - j = 0; - for (i = 0; i < 16; i++) { - if (insn & (1 << i)) { - if (is_load) { - /* load */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - if (user) { - tmp2 = tcg_const_i32(i); - gen_helper_set_user_reg(cpu_env, tmp2, tmp); - tcg_temp_free_i32(tmp2); - tcg_temp_free_i32(tmp); - } else if (i == rn) { - loaded_var = tmp; - loaded_base = 1; - } else if (i == 15 && exc_return) { - store_pc_exc_ret(s, tmp); - } else { - store_reg_from_load(s, i, tmp); - } - } else { - /* store */ - if (i == 15) { - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, read_pc(s)); - } else if (user) { - tmp = tcg_temp_new_i32(); - tmp2 = tcg_const_i32(i); - gen_helper_get_user_reg(tmp, cpu_env, tmp2); - tcg_temp_free_i32(tmp2); - } else { - tmp = load_reg(s, i); - } - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp); - } - j++; - /* no need to add after the last transfer */ - if (j != n) - tcg_gen_addi_i32(addr, addr, 4); - } - } - if (insn & (1 << 21)) { - /* write back */ - if (insn & (1 << 23)) { - if (insn & (1 << 24)) { - /* pre increment */ - } else { - /* post increment */ - tcg_gen_addi_i32(addr, addr, 4); - } - } else { - if (insn & (1 << 24)) { - /* pre decrement */ - if (n != 1) - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); - } else { - /* post decrement */ - tcg_gen_addi_i32(addr, addr, -(n * 4)); - } - } - store_reg(s, rn, addr); - } else { - tcg_temp_free_i32(addr); - } - if (loaded_base) { - store_reg(s, rn, loaded_var); - } - if (exc_return) { - /* Restore CPSR from SPSR. */ - tmp = load_cpu_field(spsr); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_cpsr_write_eret(cpu_env, tmp); - tcg_temp_free_i32(tmp); - /* Must exit loop to check un-masked IRQs */ - s->base.is_jmp = DISAS_EXIT; - } - } - break; - case 0xa: - case 0xb: - { - int32_t offset; - - /* branch (and link) */ - if (insn & (1 << 24)) { - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, s->base.pc_next); - store_reg(s, 14, tmp); - } - offset = sextract32(insn << 2, 0, 26); - gen_jmp(s, read_pc(s) + offset); - } - break; - case 0xc: - case 0xd: - case 0xe: - if (((insn >> 8) & 0xe) == 10) { - /* VFP. */ - if (disas_vfp_insn(s, insn)) { - goto illegal_op; - } - } else if (disas_coproc_insn(s, insn)) { - /* Coprocessor. */ - goto illegal_op; - } - break; - case 0xf: - /* swi */ - gen_set_pc_im(s, s->base.pc_next); - s->svc_imm = extract32(insn, 0, 24); - s->base.is_jmp = DISAS_SWI; - break; - default: - illegal_op: - unallocated_encoding(s); - break; - } + break; + default: + illegal_op: + unallocated_encoding(s); + break; } } @@ -9246,104 +10608,9 @@ static bool thumb_insn_is_16bit(DisasContext *s, uint32_t pc, uint32_t insn) return true; } -/* Return true if this is a Thumb-2 logical op. */ -static int -thumb2_logic_op(int op) -{ - return (op < 8); -} - -/* Generate code for a Thumb-2 data processing operation. If CONDS is nonzero - then set condition code flags based on the result of the operation. - If SHIFTER_OUT is nonzero then set the carry flag for logical operations - to the high bit of T1. - Returns zero if the opcode is valid. */ - -static int -gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, - TCGv_i32 t0, TCGv_i32 t1) -{ - int logic_cc; - - logic_cc = 0; - switch (op) { - case 0: /* and */ - tcg_gen_and_i32(t0, t0, t1); - logic_cc = conds; - break; - case 1: /* bic */ - tcg_gen_andc_i32(t0, t0, t1); - logic_cc = conds; - break; - case 2: /* orr */ - tcg_gen_or_i32(t0, t0, t1); - logic_cc = conds; - break; - case 3: /* orn */ - tcg_gen_orc_i32(t0, t0, t1); - logic_cc = conds; - break; - case 4: /* eor */ - tcg_gen_xor_i32(t0, t0, t1); - logic_cc = conds; - break; - case 8: /* add */ - if (conds) - gen_add_CC(t0, t0, t1); - else - tcg_gen_add_i32(t0, t0, t1); - break; - case 10: /* adc */ - if (conds) - gen_adc_CC(t0, t0, t1); - else - gen_adc(t0, t1); - break; - case 11: /* sbc */ - if (conds) { - gen_sbc_CC(t0, t0, t1); - } else { - gen_sub_carry(t0, t0, t1); - } - break; - case 13: /* sub */ - if (conds) - gen_sub_CC(t0, t0, t1); - else - tcg_gen_sub_i32(t0, t0, t1); - break; - case 14: /* rsb */ - if (conds) - gen_sub_CC(t0, t1, t0); - else - tcg_gen_sub_i32(t0, t1, t0); - break; - default: /* 5, 6, 7, 9, 12, 15. */ - return 1; - } - if (logic_cc) { - gen_logic_CC(t0); - if (shifter_out) - gen_set_CF_bit31(t1); - } - return 0; -} - /* Translate a 32-bit thumb instruction. */ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) { - uint32_t imm, shift, offset; - uint32_t rd, rn, rm, rs; - TCGv_i32 tmp; - TCGv_i32 tmp2; - TCGv_i32 tmp3; - TCGv_i32 addr; - TCGv_i64 tmp64; - int op; - int shiftop; - int conds; - int logic_cc; - /* * ARMv6-M supports a limited subset of Thumb2 instructions. * Other Thumb1 architectures allow only 32-bit @@ -9379,800 +10646,15 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) ARCH(6T2); } - rn = (insn >> 16) & 0xf; - rs = (insn >> 12) & 0xf; - rd = (insn >> 8) & 0xf; - rm = insn & 0xf; + if (disas_t32(s, insn)) { + return; + } + /* fall back to legacy decoder */ + switch ((insn >> 25) & 0xf) { case 0: case 1: case 2: case 3: /* 16-bit instructions. Should never happen. */ abort(); - case 4: - if (insn & (1 << 22)) { - /* 0b1110_100x_x1xx_xxxx_xxxx_xxxx_xxxx_xxxx - * - load/store doubleword, load/store exclusive, ldacq/strel, - * table branch, TT. - */ - if (insn == 0xe97fe97f && arm_dc_feature(s, ARM_FEATURE_M) && - arm_dc_feature(s, ARM_FEATURE_V8)) { - /* 0b1110_1001_0111_1111_1110_1001_0111_111 - * - SG (v8M only) - * The bulk of the behaviour for this instruction is implemented - * in v7m_handle_execute_nsc(), which deals with the insn when - * it is executed by a CPU in non-secure state from memory - * which is Secure & NonSecure-Callable. - * Here we only need to handle the remaining cases: - * * in NS memory (including the "security extension not - * implemented" case) : NOP - * * in S memory but CPU already secure (clear IT bits) - * We know that the attribute for the memory this insn is - * in must match the current CPU state, because otherwise - * get_phys_addr_pmsav8 would have generated an exception. - */ - if (s->v8m_secure) { - /* Like the IT insn, we don't need to generate any code */ - s->condexec_cond = 0; - s->condexec_mask = 0; - } - } else if (insn & 0x01200000) { - /* 0b1110_1000_x11x_xxxx_xxxx_xxxx_xxxx_xxxx - * - load/store dual (post-indexed) - * 0b1111_1001_x10x_xxxx_xxxx_xxxx_xxxx_xxxx - * - load/store dual (literal and immediate) - * 0b1111_1001_x11x_xxxx_xxxx_xxxx_xxxx_xxxx - * - load/store dual (pre-indexed) - */ - bool wback = extract32(insn, 21, 1); - - if (rn == 15 && (insn & (1 << 21))) { - /* UNPREDICTABLE */ - goto illegal_op; - } - - addr = add_reg_for_lit(s, rn, 0); - offset = (insn & 0xff) * 4; - if ((insn & (1 << 23)) == 0) { - offset = -offset; - } - - if (s->v8m_stackcheck && rn == 13 && wback) { - /* - * Here 'addr' is the current SP; if offset is +ve we're - * moving SP up, else down. It is UNKNOWN whether the limit - * check triggers when SP starts below the limit and ends - * up above it; check whichever of the current and final - * SP is lower, so QEMU will trigger in that situation. - */ - if ((int32_t)offset < 0) { - TCGv_i32 newsp = tcg_temp_new_i32(); - - tcg_gen_addi_i32(newsp, addr, offset); - gen_helper_v8m_stackcheck(cpu_env, newsp); - tcg_temp_free_i32(newsp); - } else { - gen_helper_v8m_stackcheck(cpu_env, addr); - } - } - - if (insn & (1 << 24)) { - tcg_gen_addi_i32(addr, addr, offset); - offset = 0; - } - if (insn & (1 << 20)) { - /* ldrd */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - store_reg(s, rs, tmp); - tcg_gen_addi_i32(addr, addr, 4); - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - store_reg(s, rd, tmp); - } else { - /* strd */ - tmp = load_reg(s, rs); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp); - tcg_gen_addi_i32(addr, addr, 4); - tmp = load_reg(s, rd); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp); - } - if (wback) { - /* Base writeback. */ - tcg_gen_addi_i32(addr, addr, offset - 4); - store_reg(s, rn, addr); - } else { - tcg_temp_free_i32(addr); - } - } else if ((insn & (1 << 23)) == 0) { - /* 0b1110_1000_010x_xxxx_xxxx_xxxx_xxxx_xxxx - * - load/store exclusive word - * - TT (v8M only) - */ - if (rs == 15) { - if (!(insn & (1 << 20)) && - arm_dc_feature(s, ARM_FEATURE_M) && - arm_dc_feature(s, ARM_FEATURE_V8)) { - /* 0b1110_1000_0100_xxxx_1111_xxxx_xxxx_xxxx - * - TT (v8M only) - */ - bool alt = insn & (1 << 7); - TCGv_i32 addr, op, ttresp; - - if ((insn & 0x3f) || rd == 13 || rd == 15 || rn == 15) { - /* we UNDEF for these UNPREDICTABLE cases */ - goto illegal_op; - } - - if (alt && !s->v8m_secure) { - goto illegal_op; - } - - addr = load_reg(s, rn); - op = tcg_const_i32(extract32(insn, 6, 2)); - ttresp = tcg_temp_new_i32(); - gen_helper_v7m_tt(ttresp, cpu_env, addr, op); - tcg_temp_free_i32(addr); - tcg_temp_free_i32(op); - store_reg(s, rd, ttresp); - break; - } - goto illegal_op; - } - addr = tcg_temp_local_new_i32(); - load_reg_var(s, addr, rn); - tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2); - if (insn & (1 << 20)) { - gen_load_exclusive(s, rs, 15, addr, 2); - } else { - gen_store_exclusive(s, rd, rs, 15, addr, 2); - } - tcg_temp_free_i32(addr); - } else if ((insn & (7 << 5)) == 0) { - /* Table Branch. */ - addr = load_reg(s, rn); - tmp = load_reg(s, rm); - tcg_gen_add_i32(addr, addr, tmp); - if (insn & (1 << 4)) { - /* tbh */ - tcg_gen_add_i32(addr, addr, tmp); - tcg_temp_free_i32(tmp); - tmp = tcg_temp_new_i32(); - gen_aa32_ld16u(s, tmp, addr, get_mem_index(s)); - } else { /* tbb */ - tcg_temp_free_i32(tmp); - tmp = tcg_temp_new_i32(); - gen_aa32_ld8u(s, tmp, addr, get_mem_index(s)); - } - tcg_temp_free_i32(addr); - tcg_gen_shli_i32(tmp, tmp, 1); - tcg_gen_addi_i32(tmp, tmp, read_pc(s)); - store_reg(s, 15, tmp); - } else { - bool is_lasr = false; - bool is_ld = extract32(insn, 20, 1); - int op2 = (insn >> 6) & 0x3; - op = (insn >> 4) & 0x3; - switch (op2) { - case 0: - goto illegal_op; - case 1: - /* Load/store exclusive byte/halfword/doubleword */ - if (op == 2) { - goto illegal_op; - } - ARCH(7); - break; - case 2: - /* Load-acquire/store-release */ - if (op == 3) { - goto illegal_op; - } - /* Fall through */ - case 3: - /* Load-acquire/store-release exclusive */ - ARCH(8); - is_lasr = true; - break; - } - - if (is_lasr && !is_ld) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); - } - - addr = tcg_temp_local_new_i32(); - load_reg_var(s, addr, rn); - if (!(op2 & 1)) { - if (is_ld) { - tmp = tcg_temp_new_i32(); - switch (op) { - case 0: /* ldab */ - gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), - rs | ISSIsAcqRel); - break; - case 1: /* ldah */ - gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), - rs | ISSIsAcqRel); - break; - case 2: /* lda */ - gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), - rs | ISSIsAcqRel); - break; - default: - abort(); - } - store_reg(s, rs, tmp); - } else { - tmp = load_reg(s, rs); - switch (op) { - case 0: /* stlb */ - gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), - rs | ISSIsAcqRel); - break; - case 1: /* stlh */ - gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), - rs | ISSIsAcqRel); - break; - case 2: /* stl */ - gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), - rs | ISSIsAcqRel); - break; - default: - abort(); - } - tcg_temp_free_i32(tmp); - } - } else if (is_ld) { - gen_load_exclusive(s, rs, rd, addr, op); - } else { - gen_store_exclusive(s, rm, rs, rd, addr, op); - } - tcg_temp_free_i32(addr); - - if (is_lasr && is_ld) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); - } - } - } else { - /* Load/store multiple, RFE, SRS. */ - if (((insn >> 23) & 1) == ((insn >> 24) & 1)) { - /* RFE, SRS: not available in user mode or on M profile */ - if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) { - goto illegal_op; - } - if (insn & (1 << 20)) { - /* rfe */ - addr = load_reg(s, rn); - if ((insn & (1 << 24)) == 0) - tcg_gen_addi_i32(addr, addr, -8); - /* Load PC into tmp and CPSR into tmp2. */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - tcg_gen_addi_i32(addr, addr, 4); - tmp2 = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s)); - if (insn & (1 << 21)) { - /* Base writeback. */ - if (insn & (1 << 24)) { - tcg_gen_addi_i32(addr, addr, 4); - } else { - tcg_gen_addi_i32(addr, addr, -4); - } - store_reg(s, rn, addr); - } else { - tcg_temp_free_i32(addr); - } - gen_rfe(s, tmp, tmp2); - } else { - /* srs */ - gen_srs(s, (insn & 0x1f), (insn & (1 << 24)) ? 1 : 2, - insn & (1 << 21)); - } - } else { - int i, loaded_base = 0; - TCGv_i32 loaded_var; - bool wback = extract32(insn, 21, 1); - /* Load/store multiple. */ - addr = load_reg(s, rn); - offset = 0; - for (i = 0; i < 16; i++) { - if (insn & (1 << i)) - offset += 4; - } - - if (insn & (1 << 24)) { - tcg_gen_addi_i32(addr, addr, -offset); - } - - if (s->v8m_stackcheck && rn == 13 && wback) { - /* - * If the writeback is incrementing SP rather than - * decrementing it, and the initial SP is below the - * stack limit but the final written-back SP would - * be above, then then we must not perform any memory - * accesses, but it is IMPDEF whether we generate - * an exception. We choose to do so in this case. - * At this point 'addr' is the lowest address, so - * either the original SP (if incrementing) or our - * final SP (if decrementing), so that's what we check. - */ - gen_helper_v8m_stackcheck(cpu_env, addr); - } - - loaded_var = NULL; - for (i = 0; i < 16; i++) { - if ((insn & (1 << i)) == 0) - continue; - if (insn & (1 << 20)) { - /* Load. */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - if (i == 15) { - gen_bx_excret(s, tmp); - } else if (i == rn) { - loaded_var = tmp; - loaded_base = 1; - } else { - store_reg(s, i, tmp); - } - } else { - /* Store. */ - tmp = load_reg(s, i); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp); - } - tcg_gen_addi_i32(addr, addr, 4); - } - if (loaded_base) { - store_reg(s, rn, loaded_var); - } - if (wback) { - /* Base register writeback. */ - if (insn & (1 << 24)) { - tcg_gen_addi_i32(addr, addr, -offset); - } - /* Fault if writeback register is in register list. */ - if (insn & (1 << rn)) - goto illegal_op; - store_reg(s, rn, addr); - } else { - tcg_temp_free_i32(addr); - } - } - } - break; - case 5: - - op = (insn >> 21) & 0xf; - if (op == 6) { - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - goto illegal_op; - } - /* Halfword pack. */ - tmp = load_reg(s, rn); - tmp2 = load_reg(s, rm); - shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3); - if (insn & (1 << 5)) { - /* pkhtb */ - if (shift == 0) { - shift = 31; - } - tcg_gen_sari_i32(tmp2, tmp2, shift); - tcg_gen_deposit_i32(tmp, tmp, tmp2, 0, 16); - } else { - /* pkhbt */ - tcg_gen_shli_i32(tmp2, tmp2, shift); - tcg_gen_deposit_i32(tmp, tmp2, tmp, 0, 16); - } - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - } else { - /* Data processing register constant shift. */ - if (rn == 15) { - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, 0); - } else { - tmp = load_reg(s, rn); - } - tmp2 = load_reg(s, rm); - - shiftop = (insn >> 4) & 3; - shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); - conds = (insn & (1 << 20)) != 0; - logic_cc = (conds && thumb2_logic_op(op)); - gen_arm_shift_im(tmp2, shiftop, shift, logic_cc); - if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2)) - goto illegal_op; - tcg_temp_free_i32(tmp2); - if (rd == 13 && - ((op == 2 && rn == 15) || - (op == 8 && rn == 13) || - (op == 13 && rn == 13))) { - /* MOV SP, ... or ADD SP, SP, ... or SUB SP, SP, ... */ - store_sp_checked(s, tmp); - } else if (rd != 15) { - store_reg(s, rd, tmp); - } else { - tcg_temp_free_i32(tmp); - } - } - break; - case 13: /* Misc data processing. */ - op = ((insn >> 22) & 6) | ((insn >> 7) & 1); - if (op < 4 && (insn & 0xf000) != 0xf000) - goto illegal_op; - switch (op) { - case 0: /* Register controlled shift. */ - tmp = load_reg(s, rn); - tmp2 = load_reg(s, rm); - if ((insn & 0x70) != 0) - goto illegal_op; - /* - * 0b1111_1010_0xxx_xxxx_1111_xxxx_0000_xxxx: - * - MOV, MOVS (register-shifted register), flagsetting - */ - op = (insn >> 21) & 3; - logic_cc = (insn & (1 << 20)) != 0; - gen_arm_shift_reg(tmp, op, tmp2, logic_cc); - if (logic_cc) - gen_logic_CC(tmp); - store_reg(s, rd, tmp); - break; - case 1: /* Sign/zero extend. */ - op = (insn >> 20) & 7; - switch (op) { - case 0: /* SXTAH, SXTH */ - case 1: /* UXTAH, UXTH */ - case 4: /* SXTAB, SXTB */ - case 5: /* UXTAB, UXTB */ - break; - case 2: /* SXTAB16, SXTB16 */ - case 3: /* UXTAB16, UXTB16 */ - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - goto illegal_op; - } - break; - default: - goto illegal_op; - } - if (rn != 15) { - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - goto illegal_op; - } - } - tmp = load_reg(s, rm); - shift = (insn >> 4) & 3; - /* ??? In many cases it's not necessary to do a - rotate, a shift is sufficient. */ - tcg_gen_rotri_i32(tmp, tmp, shift * 8); - op = (insn >> 20) & 7; - switch (op) { - case 0: gen_sxth(tmp); break; - case 1: gen_uxth(tmp); break; - case 2: gen_sxtb16(tmp); break; - case 3: gen_uxtb16(tmp); break; - case 4: gen_sxtb(tmp); break; - case 5: gen_uxtb(tmp); break; - default: - g_assert_not_reached(); - } - if (rn != 15) { - tmp2 = load_reg(s, rn); - if ((op >> 1) == 1) { - gen_add16(tmp, tmp2); - } else { - tcg_gen_add_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - } - store_reg(s, rd, tmp); - break; - case 2: /* SIMD add/subtract. */ - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - goto illegal_op; - } - op = (insn >> 20) & 7; - shift = (insn >> 4) & 7; - if ((op & 3) == 3 || (shift & 3) == 3) - goto illegal_op; - tmp = load_reg(s, rn); - tmp2 = load_reg(s, rm); - gen_thumb2_parallel_addsub(op, shift, tmp, tmp2); - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - break; - case 3: /* Other data processing. */ - op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7); - if (op < 4) { - /* Saturating add/subtract. */ - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - goto illegal_op; - } - tmp = load_reg(s, rn); - tmp2 = load_reg(s, rm); - if (op & 1) - gen_helper_add_saturate(tmp, cpu_env, tmp, tmp); - if (op & 2) - gen_helper_sub_saturate(tmp, cpu_env, tmp2, tmp); - else - gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } else { - switch (op) { - case 0x0a: /* rbit */ - case 0x08: /* rev */ - case 0x09: /* rev16 */ - case 0x0b: /* revsh */ - case 0x18: /* clz */ - break; - case 0x10: /* sel */ - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - goto illegal_op; - } - break; - case 0x20: /* crc32/crc32c */ - case 0x21: - case 0x22: - case 0x28: - case 0x29: - case 0x2a: - if (!dc_isar_feature(aa32_crc32, s)) { - goto illegal_op; - } - break; - default: - goto illegal_op; - } - tmp = load_reg(s, rn); - switch (op) { - case 0x0a: /* rbit */ - gen_helper_rbit(tmp, tmp); - break; - case 0x08: /* rev */ - tcg_gen_bswap32_i32(tmp, tmp); - break; - case 0x09: /* rev16 */ - gen_rev16(tmp); - break; - case 0x0b: /* revsh */ - gen_revsh(tmp); - break; - case 0x10: /* sel */ - tmp2 = load_reg(s, rm); - tmp3 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE)); - gen_helper_sel_flags(tmp, tmp3, tmp, tmp2); - tcg_temp_free_i32(tmp3); - tcg_temp_free_i32(tmp2); - break; - case 0x18: /* clz */ - tcg_gen_clzi_i32(tmp, tmp, 32); - break; - case 0x20: - case 0x21: - case 0x22: - case 0x28: - case 0x29: - case 0x2a: - { - /* crc32/crc32c */ - uint32_t sz = op & 0x3; - uint32_t c = op & 0x8; - - tmp2 = load_reg(s, rm); - if (sz == 0) { - tcg_gen_andi_i32(tmp2, tmp2, 0xff); - } else if (sz == 1) { - tcg_gen_andi_i32(tmp2, tmp2, 0xffff); - } - tmp3 = tcg_const_i32(1 << sz); - if (c) { - gen_helper_crc32c(tmp, tmp, tmp2, tmp3); - } else { - gen_helper_crc32(tmp, tmp, tmp2, tmp3); - } - tcg_temp_free_i32(tmp2); - tcg_temp_free_i32(tmp3); - break; - } - default: - g_assert_not_reached(); - } - } - store_reg(s, rd, tmp); - break; - case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */ - switch ((insn >> 20) & 7) { - case 0: /* 32 x 32 -> 32 */ - case 7: /* Unsigned sum of absolute differences. */ - break; - case 1: /* 16 x 16 -> 32 */ - case 2: /* Dual multiply add. */ - case 3: /* 32 * 16 -> 32msb */ - case 4: /* Dual multiply subtract. */ - case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */ - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - goto illegal_op; - } - break; - } - op = (insn >> 4) & 0xf; - tmp = load_reg(s, rn); - tmp2 = load_reg(s, rm); - switch ((insn >> 20) & 7) { - case 0: /* 32 x 32 -> 32 */ - tcg_gen_mul_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - if (rs != 15) { - tmp2 = load_reg(s, rs); - if (op) - tcg_gen_sub_i32(tmp, tmp2, tmp); - else - tcg_gen_add_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - break; - case 1: /* 16 x 16 -> 32 */ - gen_mulxy(tmp, tmp2, op & 2, op & 1); - tcg_temp_free_i32(tmp2); - if (rs != 15) { - tmp2 = load_reg(s, rs); - gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - break; - case 2: /* Dual multiply add. */ - case 4: /* Dual multiply subtract. */ - if (op) - gen_swap_half(tmp2); - gen_smul_dual(tmp, tmp2); - if (insn & (1 << 22)) { - /* This subtraction cannot overflow. */ - tcg_gen_sub_i32(tmp, tmp, tmp2); - } else { - /* This addition cannot overflow 32 bits; - * however it may overflow considered as a signed - * operation, in which case we must set the Q flag. - */ - gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); - } - tcg_temp_free_i32(tmp2); - if (rs != 15) - { - tmp2 = load_reg(s, rs); - gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - break; - case 3: /* 32 * 16 -> 32msb */ - if (op) - tcg_gen_sari_i32(tmp2, tmp2, 16); - else - gen_sxth(tmp2); - tmp64 = gen_muls_i64_i32(tmp, tmp2); - tcg_gen_shri_i64(tmp64, tmp64, 16); - tmp = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(tmp, tmp64); - tcg_temp_free_i64(tmp64); - if (rs != 15) - { - tmp2 = load_reg(s, rs); - gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - break; - case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */ - tcg_gen_muls2_i32(tmp2, tmp, tmp, tmp2); - if (rs != 15) { - tmp3 = load_reg(s, rs); - if (insn & (1 << 20)) { - tcg_gen_add_i32(tmp, tmp, tmp3); - } else { - tcg_gen_sub_i32(tmp, tmp, tmp3); - } - tcg_temp_free_i32(tmp3); - } - if (insn & (1 << 4)) { - /* - * Adding 0x80000000 to the 64-bit quantity - * means that we have carry in to the high - * word when the low word has the high bit set. - */ - tcg_gen_shri_i32(tmp2, tmp2, 31); - tcg_gen_add_i32(tmp, tmp, tmp2); - } - tcg_temp_free_i32(tmp2); - break; - case 7: /* Unsigned sum of absolute differences. */ - gen_helper_usad8(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - if (rs != 15) { - tmp2 = load_reg(s, rs); - tcg_gen_add_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - } - break; - } - store_reg(s, rd, tmp); - break; - case 6: case 7: /* 64-bit multiply, Divide. */ - op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70); - tmp = load_reg(s, rn); - tmp2 = load_reg(s, rm); - if ((op & 0x50) == 0x10) { - /* sdiv, udiv */ - if (!dc_isar_feature(thumb_div, s)) { - goto illegal_op; - } - if (op & 0x20) - gen_helper_udiv(tmp, tmp, tmp2); - else - gen_helper_sdiv(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - } else if ((op & 0xe) == 0xc) { - /* Dual multiply accumulate long. */ - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - goto illegal_op; - } - if (op & 1) - gen_swap_half(tmp2); - gen_smul_dual(tmp, tmp2); - if (op & 0x10) { - tcg_gen_sub_i32(tmp, tmp, tmp2); - } else { - tcg_gen_add_i32(tmp, tmp, tmp2); - } - tcg_temp_free_i32(tmp2); - /* BUGFIX */ - tmp64 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp64, tmp); - tcg_temp_free_i32(tmp); - gen_addq(s, tmp64, rs, rd); - gen_storeq_reg(s, rs, rd, tmp64); - tcg_temp_free_i64(tmp64); - } else { - if (op & 0x20) { - /* Unsigned 64-bit multiply */ - tmp64 = gen_mulu_i64_i32(tmp, tmp2); - } else { - if (op & 8) { - /* smlalxy */ - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - tcg_temp_free_i32(tmp2); - tcg_temp_free_i32(tmp); - goto illegal_op; - } - gen_mulxy(tmp, tmp2, op & 2, op & 1); - tcg_temp_free_i32(tmp2); - tmp64 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp64, tmp); - tcg_temp_free_i32(tmp); - } else { - /* Signed 64-bit multiply */ - tmp64 = gen_muls_i64_i32(tmp, tmp2); - } - } - if (op & 4) { - /* umaal */ - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - tcg_temp_free_i64(tmp64); - goto illegal_op; - } - gen_addq_lo(s, tmp64, rs); - gen_addq_lo(s, tmp64, rd); - } else if (op & 0x40) { - /* 64-bit accumulate. */ - gen_addq(s, tmp64, rs, rd); - } - gen_storeq_reg(s, rs, rd, tmp64); - tcg_temp_free_i64(tmp64); - } - break; - } - break; case 6: case 7: case 14: case 15: /* Coprocessor. */ if (arm_dc_feature(s, ARM_FEATURE_M)) { @@ -10201,6 +10683,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) } if (arm_dc_feature(s, ARM_FEATURE_VFP)) { + uint32_t rn = (insn >> 16) & 0xf; TCGv_i32 fptr = load_reg(s, rn); if (extract32(insn, 20, 1)) { @@ -10259,1457 +10742,25 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) } } break; - case 8: case 9: case 10: case 11: - if (insn & (1 << 15)) { - /* Branches, misc control. */ - if (insn & 0x5000) { - /* Unconditional branch. */ - /* signextend(hw1[10:0]) -> offset[:12]. */ - offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff; - /* hw1[10:0] -> offset[11:1]. */ - offset |= (insn & 0x7ff) << 1; - /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22] - offset[24:22] already have the same value because of the - sign extension above. */ - offset ^= ((~insn) & (1 << 13)) << 10; - offset ^= ((~insn) & (1 << 11)) << 11; - - if (insn & (1 << 14)) { - /* Branch and link. */ - tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1); - } - - offset += read_pc(s); - if (insn & (1 << 12)) { - /* b/bl */ - gen_jmp(s, offset); - } else { - /* blx */ - offset &= ~(uint32_t)2; - /* thumb2 bx, no need to check */ - gen_bx_im(s, offset); - } - } else if (((insn >> 23) & 7) == 7) { - /* Misc control */ - if (insn & (1 << 13)) - goto illegal_op; - - if (insn & (1 << 26)) { - if (arm_dc_feature(s, ARM_FEATURE_M)) { - goto illegal_op; - } - if (!(insn & (1 << 20))) { - /* Hypervisor call (v7) */ - int imm16 = extract32(insn, 16, 4) << 12 - | extract32(insn, 0, 12); - ARCH(7); - if (IS_USER(s)) { - goto illegal_op; - } - gen_hvc(s, imm16); - } else { - /* Secure monitor call (v6+) */ - ARCH(6K); - if (IS_USER(s)) { - goto illegal_op; - } - gen_smc(s); - } - } else { - op = (insn >> 20) & 7; - switch (op) { - case 0: /* msr cpsr. */ - if (arm_dc_feature(s, ARM_FEATURE_M)) { - tmp = load_reg(s, rn); - /* the constant is the mask and SYSm fields */ - addr = tcg_const_i32(insn & 0xfff); - gen_helper_v7m_msr(cpu_env, addr, tmp); - tcg_temp_free_i32(addr); - tcg_temp_free_i32(tmp); - gen_lookup_tb(s); - break; - } - /* fall through */ - case 1: /* msr spsr. */ - if (arm_dc_feature(s, ARM_FEATURE_M)) { - goto illegal_op; - } - - if (extract32(insn, 5, 1)) { - /* MSR (banked) */ - int sysm = extract32(insn, 8, 4) | - (extract32(insn, 4, 1) << 4); - int r = op & 1; - - gen_msr_banked(s, r, sysm, rm); - break; - } - - /* MSR (for PSRs) */ - tmp = load_reg(s, rn); - if (gen_set_psr(s, - msr_mask(s, (insn >> 8) & 0xf, op == 1), - op == 1, tmp)) - goto illegal_op; - break; - case 2: /* cps, nop-hint. */ - if (((insn >> 8) & 7) == 0) { - gen_nop_hint(s, insn & 0xff); - } - /* Implemented as NOP in user mode. */ - if (IS_USER(s)) - break; - offset = 0; - imm = 0; - if (insn & (1 << 10)) { - if (insn & (1 << 7)) - offset |= CPSR_A; - if (insn & (1 << 6)) - offset |= CPSR_I; - if (insn & (1 << 5)) - offset |= CPSR_F; - if (insn & (1 << 9)) - imm = CPSR_A | CPSR_I | CPSR_F; - } - if (insn & (1 << 8)) { - offset |= 0x1f; - imm |= (insn & 0x1f); - } - if (offset) { - gen_set_psr_im(s, offset, 0, imm); - } - break; - case 3: /* Special control operations. */ - if (!arm_dc_feature(s, ARM_FEATURE_V7) && - !arm_dc_feature(s, ARM_FEATURE_M)) { - goto illegal_op; - } - op = (insn >> 4) & 0xf; - switch (op) { - case 2: /* clrex */ - gen_clrex(s); - break; - case 4: /* dsb */ - case 5: /* dmb */ - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); - break; - case 6: /* isb */ - /* We need to break the TB after this insn - * to execute self-modifying code correctly - * and also to take any pending interrupts - * immediately. - */ - gen_goto_tb(s, 0, s->base.pc_next); - break; - case 7: /* sb */ - if ((insn & 0xf) || !dc_isar_feature(aa32_sb, s)) { - goto illegal_op; - } - /* - * TODO: There is no speculation barrier opcode - * for TCG; MB and end the TB instead. - */ - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); - gen_goto_tb(s, 0, s->base.pc_next); - break; - default: - goto illegal_op; - } - break; - case 4: /* bxj */ - /* Trivial implementation equivalent to bx. - * This instruction doesn't exist at all for M-profile. - */ - if (arm_dc_feature(s, ARM_FEATURE_M)) { - goto illegal_op; - } - tmp = load_reg(s, rn); - gen_bx(s, tmp); - break; - case 5: /* Exception return. */ - if (IS_USER(s)) { - goto illegal_op; - } - if (rn != 14 || rd != 15) { - goto illegal_op; - } - if (s->current_el == 2) { - /* ERET from Hyp uses ELR_Hyp, not LR */ - if (insn & 0xff) { - goto illegal_op; - } - tmp = load_cpu_field(elr_el[2]); - } else { - tmp = load_reg(s, rn); - tcg_gen_subi_i32(tmp, tmp, insn & 0xff); - } - gen_exception_return(s, tmp); - break; - case 6: /* MRS */ - if (extract32(insn, 5, 1) && - !arm_dc_feature(s, ARM_FEATURE_M)) { - /* MRS (banked) */ - int sysm = extract32(insn, 16, 4) | - (extract32(insn, 4, 1) << 4); - - gen_mrs_banked(s, 0, sysm, rd); - break; - } - - if (extract32(insn, 16, 4) != 0xf) { - goto illegal_op; - } - if (!arm_dc_feature(s, ARM_FEATURE_M) && - extract32(insn, 0, 8) != 0) { - goto illegal_op; - } - - /* mrs cpsr */ - tmp = tcg_temp_new_i32(); - if (arm_dc_feature(s, ARM_FEATURE_M)) { - addr = tcg_const_i32(insn & 0xff); - gen_helper_v7m_mrs(tmp, cpu_env, addr); - tcg_temp_free_i32(addr); - } else { - gen_helper_cpsr_read(tmp, cpu_env); - } - store_reg(s, rd, tmp); - break; - case 7: /* MRS */ - if (extract32(insn, 5, 1) && - !arm_dc_feature(s, ARM_FEATURE_M)) { - /* MRS (banked) */ - int sysm = extract32(insn, 16, 4) | - (extract32(insn, 4, 1) << 4); - - gen_mrs_banked(s, 1, sysm, rd); - break; - } - - /* mrs spsr. */ - /* Not accessible in user mode. */ - if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) { - goto illegal_op; - } - - if (extract32(insn, 16, 4) != 0xf || - extract32(insn, 0, 8) != 0) { - goto illegal_op; - } - - tmp = load_cpu_field(spsr); - store_reg(s, rd, tmp); - break; - } - } - } else { - /* Conditional branch. */ - op = (insn >> 22) & 0xf; - /* Generate a conditional jump to next instruction. */ - arm_skip_unless(s, op); - - /* offset[11:1] = insn[10:0] */ - offset = (insn & 0x7ff) << 1; - /* offset[17:12] = insn[21:16]. */ - offset |= (insn & 0x003f0000) >> 4; - /* offset[31:20] = insn[26]. */ - offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11; - /* offset[18] = insn[13]. */ - offset |= (insn & (1 << 13)) << 5; - /* offset[19] = insn[11]. */ - offset |= (insn & (1 << 11)) << 8; - - /* jump to the offset */ - gen_jmp(s, read_pc(s) + offset); - } - } else { - /* - * 0b1111_0xxx_xxxx_0xxx_xxxx_xxxx - * - Data-processing (modified immediate, plain binary immediate) - */ - if (insn & (1 << 25)) { - /* - * 0b1111_0x1x_xxxx_0xxx_xxxx_xxxx - * - Data-processing (plain binary immediate) - */ - if (insn & (1 << 24)) { - if (insn & (1 << 20)) - goto illegal_op; - /* Bitfield/Saturate. */ - op = (insn >> 21) & 7; - imm = insn & 0x1f; - shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); - if (rn == 15) { - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, 0); - } else { - tmp = load_reg(s, rn); - } - switch (op) { - case 2: /* Signed bitfield extract. */ - imm++; - if (shift + imm > 32) - goto illegal_op; - if (imm < 32) { - tcg_gen_sextract_i32(tmp, tmp, shift, imm); - } - break; - case 6: /* Unsigned bitfield extract. */ - imm++; - if (shift + imm > 32) - goto illegal_op; - if (imm < 32) { - tcg_gen_extract_i32(tmp, tmp, shift, imm); - } - break; - case 3: /* Bitfield insert/clear. */ - if (imm < shift) - goto illegal_op; - imm = imm + 1 - shift; - if (imm != 32) { - tmp2 = load_reg(s, rd); - tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, imm); - tcg_temp_free_i32(tmp2); - } - break; - case 7: - goto illegal_op; - default: /* Saturate. */ - if (op & 1) { - tcg_gen_sari_i32(tmp, tmp, shift); - } else { - tcg_gen_shli_i32(tmp, tmp, shift); - } - tmp2 = tcg_const_i32(imm); - if (op & 4) { - /* Unsigned. */ - if ((op & 1) && shift == 0) { - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - goto illegal_op; - } - gen_helper_usat16(tmp, cpu_env, tmp, tmp2); - } else { - gen_helper_usat(tmp, cpu_env, tmp, tmp2); - } - } else { - /* Signed. */ - if ((op & 1) && shift == 0) { - if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - goto illegal_op; - } - gen_helper_ssat16(tmp, cpu_env, tmp, tmp2); - } else { - gen_helper_ssat(tmp, cpu_env, tmp, tmp2); - } - } - tcg_temp_free_i32(tmp2); - break; - } - store_reg(s, rd, tmp); - } else { - imm = ((insn & 0x04000000) >> 15) - | ((insn & 0x7000) >> 4) | (insn & 0xff); - if (insn & (1 << 22)) { - /* 16-bit immediate. */ - imm |= (insn >> 4) & 0xf000; - if (insn & (1 << 23)) { - /* movt */ - tmp = load_reg(s, rd); - tcg_gen_ext16u_i32(tmp, tmp); - tcg_gen_ori_i32(tmp, tmp, imm << 16); - } else { - /* movw */ - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, imm); - } - store_reg(s, rd, tmp); - } else { - /* Add/sub 12-bit immediate. */ - if (insn & (1 << 23)) { - imm = -imm; - } - tmp = add_reg_for_lit(s, rn, imm); - if (rn == 13 && rd == 13) { - /* ADD SP, SP, imm or SUB SP, SP, imm */ - store_sp_checked(s, tmp); - } else { - store_reg(s, rd, tmp); - } - } - } - } else { - /* - * 0b1111_0x0x_xxxx_0xxx_xxxx_xxxx - * - Data-processing (modified immediate) - */ - int shifter_out = 0; - /* modified 12-bit immediate. */ - shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12); - imm = (insn & 0xff); - switch (shift) { - case 0: /* XY */ - /* Nothing to do. */ - break; - case 1: /* 00XY00XY */ - imm |= imm << 16; - break; - case 2: /* XY00XY00 */ - imm |= imm << 16; - imm <<= 8; - break; - case 3: /* XYXYXYXY */ - imm |= imm << 16; - imm |= imm << 8; - break; - default: /* Rotated constant. */ - shift = (shift << 1) | (imm >> 7); - imm |= 0x80; - imm = imm << (32 - shift); - shifter_out = 1; - break; - } - tmp2 = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp2, imm); - rn = (insn >> 16) & 0xf; - if (rn == 15) { - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, 0); - } else { - tmp = load_reg(s, rn); - } - op = (insn >> 21) & 0xf; - if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0, - shifter_out, tmp, tmp2)) - goto illegal_op; - tcg_temp_free_i32(tmp2); - rd = (insn >> 8) & 0xf; - if (rd == 13 && rn == 13 - && (op == 8 || op == 13)) { - /* ADD(S) SP, SP, imm or SUB(S) SP, SP, imm */ - store_sp_checked(s, tmp); - } else if (rd != 15) { - store_reg(s, rd, tmp); - } else { - tcg_temp_free_i32(tmp); - } - } - } - break; - case 12: /* Load/store single data item. */ - { - int postinc = 0; - int writeback = 0; - int memidx; - ISSInfo issinfo; - + case 12: if ((insn & 0x01100000) == 0x01000000) { if (disas_neon_ls_insn(s, insn)) { goto illegal_op; } break; } - op = ((insn >> 21) & 3) | ((insn >> 22) & 4); - if (rs == 15) { - if (!(insn & (1 << 20))) { - goto illegal_op; - } - if (op != 2) { - /* Byte or halfword load space with dest == r15 : memory hints. - * Catch them early so we don't emit pointless addressing code. - * This space is a mix of: - * PLD/PLDW/PLI, which we implement as NOPs (note that unlike - * the ARM encodings, PLDW space doesn't UNDEF for non-v7MP - * cores) - * unallocated hints, which must be treated as NOPs - * UNPREDICTABLE space, which we NOP or UNDEF depending on - * which is easiest for the decoding logic - * Some space which must UNDEF - */ - int op1 = (insn >> 23) & 3; - int op2 = (insn >> 6) & 0x3f; - if (op & 2) { - goto illegal_op; - } - if (rn == 15) { - /* UNPREDICTABLE, unallocated hint or - * PLD/PLDW/PLI (literal) - */ - return; - } - if (op1 & 1) { - return; /* PLD/PLDW/PLI or unallocated hint */ - } - if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) { - return; /* PLD/PLDW/PLI or unallocated hint */ - } - /* UNDEF space, or an UNPREDICTABLE */ - goto illegal_op; - } - } - memidx = get_mem_index(s); - imm = insn & 0xfff; - if (insn & (1 << 23)) { - /* PC relative or Positive offset. */ - addr = add_reg_for_lit(s, rn, imm); - } else if (rn == 15) { - /* PC relative with negative offset. */ - addr = add_reg_for_lit(s, rn, -imm); - } else { - addr = load_reg(s, rn); - imm = insn & 0xff; - switch ((insn >> 8) & 0xf) { - case 0x0: /* Shifted Register. */ - shift = (insn >> 4) & 0xf; - if (shift > 3) { - tcg_temp_free_i32(addr); - goto illegal_op; - } - tmp = load_reg(s, rm); - tcg_gen_shli_i32(tmp, tmp, shift); - tcg_gen_add_i32(addr, addr, tmp); - tcg_temp_free_i32(tmp); - break; - case 0xc: /* Negative offset. */ - tcg_gen_addi_i32(addr, addr, -imm); - break; - case 0xe: /* User privilege. */ - tcg_gen_addi_i32(addr, addr, imm); - memidx = get_a32_user_mem_index(s); - break; - case 0x9: /* Post-decrement. */ - imm = -imm; - /* Fall through. */ - case 0xb: /* Post-increment. */ - postinc = 1; - writeback = 1; - break; - case 0xd: /* Pre-decrement. */ - imm = -imm; - /* Fall through. */ - case 0xf: /* Pre-increment. */ - writeback = 1; - break; - default: - tcg_temp_free_i32(addr); - goto illegal_op; - } - } - - issinfo = writeback ? ISSInvalid : rs; - - if (s->v8m_stackcheck && rn == 13 && writeback) { - /* - * Stackcheck. Here we know 'addr' is the current SP; - * if imm is +ve we're moving SP up, else down. It is - * UNKNOWN whether the limit check triggers when SP starts - * below the limit and ends up above it; we chose to do so. - */ - if ((int32_t)imm < 0) { - TCGv_i32 newsp = tcg_temp_new_i32(); - - tcg_gen_addi_i32(newsp, addr, imm); - gen_helper_v8m_stackcheck(cpu_env, newsp); - tcg_temp_free_i32(newsp); - } else { - gen_helper_v8m_stackcheck(cpu_env, addr); - } - } - - if (writeback && !postinc) { - tcg_gen_addi_i32(addr, addr, imm); - } - - if (insn & (1 << 20)) { - /* Load. */ - tmp = tcg_temp_new_i32(); - switch (op) { - case 0: - gen_aa32_ld8u_iss(s, tmp, addr, memidx, issinfo); - break; - case 4: - gen_aa32_ld8s_iss(s, tmp, addr, memidx, issinfo); - break; - case 1: - gen_aa32_ld16u_iss(s, tmp, addr, memidx, issinfo); - break; - case 5: - gen_aa32_ld16s_iss(s, tmp, addr, memidx, issinfo); - break; - case 2: - gen_aa32_ld32u_iss(s, tmp, addr, memidx, issinfo); - break; - default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(addr); - goto illegal_op; - } - if (rs == 15) { - gen_bx_excret(s, tmp); - } else { - store_reg(s, rs, tmp); - } - } else { - /* Store. */ - tmp = load_reg(s, rs); - switch (op) { - case 0: - gen_aa32_st8_iss(s, tmp, addr, memidx, issinfo); - break; - case 1: - gen_aa32_st16_iss(s, tmp, addr, memidx, issinfo); - break; - case 2: - gen_aa32_st32_iss(s, tmp, addr, memidx, issinfo); - break; - default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(addr); - goto illegal_op; - } - tcg_temp_free_i32(tmp); - } - if (postinc) - tcg_gen_addi_i32(addr, addr, imm); - if (writeback) { - store_reg(s, rn, addr); - } else { - tcg_temp_free_i32(addr); - } - } - break; - default: goto illegal_op; + default: + illegal_op: + unallocated_encoding(s); } - return; -illegal_op: - unallocated_encoding(s); } static void disas_thumb_insn(DisasContext *s, uint32_t insn) { - uint32_t val, op, rm, rn, rd, shift, cond; - int32_t offset; - int i; - TCGv_i32 tmp; - TCGv_i32 tmp2; - TCGv_i32 addr; - - switch (insn >> 12) { - case 0: case 1: - - rd = insn & 7; - op = (insn >> 11) & 3; - if (op == 3) { - /* - * 0b0001_1xxx_xxxx_xxxx - * - Add, subtract (three low registers) - * - Add, subtract (two low registers and immediate) - */ - rn = (insn >> 3) & 7; - tmp = load_reg(s, rn); - if (insn & (1 << 10)) { - /* immediate */ - tmp2 = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp2, (insn >> 6) & 7); - } else { - /* reg */ - rm = (insn >> 6) & 7; - tmp2 = load_reg(s, rm); - } - if (insn & (1 << 9)) { - if (s->condexec_mask) - tcg_gen_sub_i32(tmp, tmp, tmp2); - else - gen_sub_CC(tmp, tmp, tmp2); - } else { - if (s->condexec_mask) - tcg_gen_add_i32(tmp, tmp, tmp2); - else - gen_add_CC(tmp, tmp, tmp2); - } - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - } else { - /* shift immediate */ - rm = (insn >> 3) & 7; - shift = (insn >> 6) & 0x1f; - tmp = load_reg(s, rm); - gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0); - if (!s->condexec_mask) - gen_logic_CC(tmp); - store_reg(s, rd, tmp); - } - break; - case 2: case 3: - /* - * 0b001x_xxxx_xxxx_xxxx - * - Add, subtract, compare, move (one low register and immediate) - */ - op = (insn >> 11) & 3; - rd = (insn >> 8) & 0x7; - if (op == 0) { /* mov */ - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, insn & 0xff); - if (!s->condexec_mask) - gen_logic_CC(tmp); - store_reg(s, rd, tmp); - } else { - tmp = load_reg(s, rd); - tmp2 = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp2, insn & 0xff); - switch (op) { - case 1: /* cmp */ - gen_sub_CC(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - break; - case 2: /* add */ - if (s->condexec_mask) - tcg_gen_add_i32(tmp, tmp, tmp2); - else - gen_add_CC(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - break; - case 3: /* sub */ - if (s->condexec_mask) - tcg_gen_sub_i32(tmp, tmp, tmp2); - else - gen_sub_CC(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - store_reg(s, rd, tmp); - break; - } - } - break; - case 4: - if (insn & (1 << 11)) { - rd = (insn >> 8) & 7; - /* load pc-relative. Bit 1 of PC is ignored. */ - addr = add_reg_for_lit(s, 15, (insn & 0xff) * 4); - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), - rd | ISSIs16Bit); - tcg_temp_free_i32(addr); - store_reg(s, rd, tmp); - break; - } - if (insn & (1 << 10)) { - /* 0b0100_01xx_xxxx_xxxx - * - data processing extended, branch and exchange - */ - rd = (insn & 7) | ((insn >> 4) & 8); - rm = (insn >> 3) & 0xf; - op = (insn >> 8) & 3; - switch (op) { - case 0: /* add */ - tmp = load_reg(s, rd); - tmp2 = load_reg(s, rm); - tcg_gen_add_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - if (rd == 13) { - /* ADD SP, SP, reg */ - store_sp_checked(s, tmp); - } else { - store_reg(s, rd, tmp); - } - break; - case 1: /* cmp */ - tmp = load_reg(s, rd); - tmp2 = load_reg(s, rm); - gen_sub_CC(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); - tcg_temp_free_i32(tmp); - break; - case 2: /* mov/cpy */ - tmp = load_reg(s, rm); - if (rd == 13) { - /* MOV SP, reg */ - store_sp_checked(s, tmp); - } else { - store_reg(s, rd, tmp); - } - break; - case 3: - { - /* 0b0100_0111_xxxx_xxxx - * - branch [and link] exchange thumb register - */ - bool link = insn & (1 << 7); - - if (insn & 3) { - goto undef; - } - if (link) { - ARCH(5); - } - if ((insn & 4)) { - /* BXNS/BLXNS: only exists for v8M with the - * security extensions, and always UNDEF if NonSecure. - * We don't implement these in the user-only mode - * either (in theory you can use them from Secure User - * mode but they are too tied in to system emulation.) - */ - if (!s->v8m_secure || IS_USER_ONLY) { - goto undef; - } - if (link) { - gen_blxns(s, rm); - } else { - gen_bxns(s, rm); - } - break; - } - /* BLX/BX */ - tmp = load_reg(s, rm); - if (link) { - val = (uint32_t)s->base.pc_next | 1; - tmp2 = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp2, val); - store_reg(s, 14, tmp2); - gen_bx(s, tmp); - } else { - /* Only BX works as exception-return, not BLX */ - gen_bx_excret(s, tmp); - } - break; - } - } - break; - } - - /* - * 0b0100_00xx_xxxx_xxxx - * - Data-processing (two low registers) - */ - rd = insn & 7; - rm = (insn >> 3) & 7; - op = (insn >> 6) & 0xf; - if (op == 2 || op == 3 || op == 4 || op == 7) { - /* the shift/rotate ops want the operands backwards */ - val = rm; - rm = rd; - rd = val; - val = 1; - } else { - val = 0; - } - - if (op == 9) { /* neg */ - tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, 0); - } else if (op != 0xf) { /* mvn doesn't read its first operand */ - tmp = load_reg(s, rd); - } else { - tmp = NULL; - } - - tmp2 = load_reg(s, rm); - switch (op) { - case 0x0: /* and */ - tcg_gen_and_i32(tmp, tmp, tmp2); - if (!s->condexec_mask) - gen_logic_CC(tmp); - break; - case 0x1: /* eor */ - tcg_gen_xor_i32(tmp, tmp, tmp2); - if (!s->condexec_mask) - gen_logic_CC(tmp); - break; - case 0x2: /* lsl */ - if (s->condexec_mask) { - gen_shl(tmp2, tmp2, tmp); - } else { - gen_helper_shl_cc(tmp2, cpu_env, tmp2, tmp); - gen_logic_CC(tmp2); - } - break; - case 0x3: /* lsr */ - if (s->condexec_mask) { - gen_shr(tmp2, tmp2, tmp); - } else { - gen_helper_shr_cc(tmp2, cpu_env, tmp2, tmp); - gen_logic_CC(tmp2); - } - break; - case 0x4: /* asr */ - if (s->condexec_mask) { - gen_sar(tmp2, tmp2, tmp); - } else { - gen_helper_sar_cc(tmp2, cpu_env, tmp2, tmp); - gen_logic_CC(tmp2); - } - break; - case 0x5: /* adc */ - if (s->condexec_mask) { - gen_adc(tmp, tmp2); - } else { - gen_adc_CC(tmp, tmp, tmp2); - } - break; - case 0x6: /* sbc */ - if (s->condexec_mask) { - gen_sub_carry(tmp, tmp, tmp2); - } else { - gen_sbc_CC(tmp, tmp, tmp2); - } - break; - case 0x7: /* ror */ - if (s->condexec_mask) { - tcg_gen_andi_i32(tmp, tmp, 0x1f); - tcg_gen_rotr_i32(tmp2, tmp2, tmp); - } else { - gen_helper_ror_cc(tmp2, cpu_env, tmp2, tmp); - gen_logic_CC(tmp2); - } - break; - case 0x8: /* tst */ - tcg_gen_and_i32(tmp, tmp, tmp2); - gen_logic_CC(tmp); - rd = 16; - break; - case 0x9: /* neg */ - if (s->condexec_mask) - tcg_gen_neg_i32(tmp, tmp2); - else - gen_sub_CC(tmp, tmp, tmp2); - break; - case 0xa: /* cmp */ - gen_sub_CC(tmp, tmp, tmp2); - rd = 16; - break; - case 0xb: /* cmn */ - gen_add_CC(tmp, tmp, tmp2); - rd = 16; - break; - case 0xc: /* orr */ - tcg_gen_or_i32(tmp, tmp, tmp2); - if (!s->condexec_mask) - gen_logic_CC(tmp); - break; - case 0xd: /* mul */ - tcg_gen_mul_i32(tmp, tmp, tmp2); - if (!s->condexec_mask) - gen_logic_CC(tmp); - break; - case 0xe: /* bic */ - tcg_gen_andc_i32(tmp, tmp, tmp2); - if (!s->condexec_mask) - gen_logic_CC(tmp); - break; - case 0xf: /* mvn */ - tcg_gen_not_i32(tmp2, tmp2); - if (!s->condexec_mask) - gen_logic_CC(tmp2); - val = 1; - rm = rd; - break; - } - if (rd != 16) { - if (val) { - store_reg(s, rm, tmp2); - if (op != 0xf) - tcg_temp_free_i32(tmp); - } else { - store_reg(s, rd, tmp); - tcg_temp_free_i32(tmp2); - } - } else { - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - } - break; - - case 5: - /* load/store register offset. */ - rd = insn & 7; - rn = (insn >> 3) & 7; - rm = (insn >> 6) & 7; - op = (insn >> 9) & 7; - addr = load_reg(s, rn); - tmp = load_reg(s, rm); - tcg_gen_add_i32(addr, addr, tmp); - tcg_temp_free_i32(tmp); - - if (op < 3) { /* store */ - tmp = load_reg(s, rd); - } else { - tmp = tcg_temp_new_i32(); - } - - switch (op) { - case 0: /* str */ - gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - break; - case 1: /* strh */ - gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - break; - case 2: /* strb */ - gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - break; - case 3: /* ldrsb */ - gen_aa32_ld8s_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - break; - case 4: /* ldr */ - gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - break; - case 5: /* ldrh */ - gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - break; - case 6: /* ldrb */ - gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - break; - case 7: /* ldrsh */ - gen_aa32_ld16s_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - break; - } - if (op >= 3) { /* load */ - store_reg(s, rd, tmp); - } else { - tcg_temp_free_i32(tmp); - } - tcg_temp_free_i32(addr); - break; - - case 6: - /* load/store word immediate offset */ - rd = insn & 7; - rn = (insn >> 3) & 7; - addr = load_reg(s, rn); - val = (insn >> 4) & 0x7c; - tcg_gen_addi_i32(addr, addr, val); - - if (insn & (1 << 11)) { - /* load */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - store_reg(s, rd, tmp); - } else { - /* store */ - tmp = load_reg(s, rd); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp); - } - tcg_temp_free_i32(addr); - break; - - case 7: - /* load/store byte immediate offset */ - rd = insn & 7; - rn = (insn >> 3) & 7; - addr = load_reg(s, rn); - val = (insn >> 6) & 0x1f; - tcg_gen_addi_i32(addr, addr, val); - - if (insn & (1 << 11)) { - /* load */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - store_reg(s, rd, tmp); - } else { - /* store */ - tmp = load_reg(s, rd); - gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - tcg_temp_free_i32(tmp); - } - tcg_temp_free_i32(addr); - break; - - case 8: - /* load/store halfword immediate offset */ - rd = insn & 7; - rn = (insn >> 3) & 7; - addr = load_reg(s, rn); - val = (insn >> 5) & 0x3e; - tcg_gen_addi_i32(addr, addr, val); - - if (insn & (1 << 11)) { - /* load */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - store_reg(s, rd, tmp); - } else { - /* store */ - tmp = load_reg(s, rd); - gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - tcg_temp_free_i32(tmp); - } - tcg_temp_free_i32(addr); - break; - - case 9: - /* load/store from stack */ - rd = (insn >> 8) & 7; - addr = load_reg(s, 13); - val = (insn & 0xff) * 4; - tcg_gen_addi_i32(addr, addr, val); - - if (insn & (1 << 11)) { - /* load */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - store_reg(s, rd, tmp); - } else { - /* store */ - tmp = load_reg(s, rd); - gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit); - tcg_temp_free_i32(tmp); - } - tcg_temp_free_i32(addr); - break; - - case 10: - /* - * 0b1010_xxxx_xxxx_xxxx - * - Add PC/SP (immediate) - */ - rd = (insn >> 8) & 7; - val = (insn & 0xff) * 4; - tmp = add_reg_for_lit(s, insn & (1 << 11) ? 13 : 15, val); - store_reg(s, rd, tmp); - break; - - case 11: - /* misc */ - op = (insn >> 8) & 0xf; - switch (op) { - case 0: - /* - * 0b1011_0000_xxxx_xxxx - * - ADD (SP plus immediate) - * - SUB (SP minus immediate) - */ - tmp = load_reg(s, 13); - val = (insn & 0x7f) * 4; - if (insn & (1 << 7)) - val = -(int32_t)val; - tcg_gen_addi_i32(tmp, tmp, val); - store_sp_checked(s, tmp); - break; - - case 2: /* sign/zero extend. */ - ARCH(6); - rd = insn & 7; - rm = (insn >> 3) & 7; - tmp = load_reg(s, rm); - switch ((insn >> 6) & 3) { - case 0: gen_sxth(tmp); break; - case 1: gen_sxtb(tmp); break; - case 2: gen_uxth(tmp); break; - case 3: gen_uxtb(tmp); break; - } - store_reg(s, rd, tmp); - break; - case 4: case 5: case 0xc: case 0xd: - /* - * 0b1011_x10x_xxxx_xxxx - * - push/pop - */ - addr = load_reg(s, 13); - if (insn & (1 << 8)) - offset = 4; - else - offset = 0; - for (i = 0; i < 8; i++) { - if (insn & (1 << i)) - offset += 4; - } - if ((insn & (1 << 11)) == 0) { - tcg_gen_addi_i32(addr, addr, -offset); - } - - if (s->v8m_stackcheck) { - /* - * Here 'addr' is the lower of "old SP" and "new SP"; - * if this is a pop that starts below the limit and ends - * above it, it is UNKNOWN whether the limit check triggers; - * we choose to trigger. - */ - gen_helper_v8m_stackcheck(cpu_env, addr); - } - - for (i = 0; i < 8; i++) { - if (insn & (1 << i)) { - if (insn & (1 << 11)) { - /* pop */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - store_reg(s, i, tmp); - } else { - /* push */ - tmp = load_reg(s, i); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp); - } - /* advance to the next address. */ - tcg_gen_addi_i32(addr, addr, 4); - } - } - tmp = NULL; - if (insn & (1 << 8)) { - if (insn & (1 << 11)) { - /* pop pc */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - /* don't set the pc until the rest of the instruction - has completed */ - } else { - /* push lr */ - tmp = load_reg(s, 14); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp); - } - tcg_gen_addi_i32(addr, addr, 4); - } - if ((insn & (1 << 11)) == 0) { - tcg_gen_addi_i32(addr, addr, -offset); - } - /* write back the new stack pointer */ - store_reg(s, 13, addr); - /* set the new PC value */ - if ((insn & 0x0900) == 0x0900) { - store_reg_from_load(s, 15, tmp); - } - break; - - case 1: case 3: case 9: case 11: /* czb */ - rm = insn & 7; - tmp = load_reg(s, rm); - arm_gen_condlabel(s); - if (insn & (1 << 11)) - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel); - else - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel); - tcg_temp_free_i32(tmp); - offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3; - gen_jmp(s, read_pc(s) + offset); - break; - - case 15: /* IT, nop-hint. */ - if ((insn & 0xf) == 0) { - gen_nop_hint(s, (insn >> 4) & 0xf); - break; - } - /* - * IT (If-Then) - * - * Combinations of firstcond and mask which set up an 0b1111 - * condition are UNPREDICTABLE; we take the CONSTRAINED - * UNPREDICTABLE choice to treat 0b1111 the same as 0b1110, - * i.e. both meaning "execute always". - */ - s->condexec_cond = (insn >> 4) & 0xe; - s->condexec_mask = insn & 0x1f; - /* No actual code generated for this insn, just setup state. */ - break; - - case 0xe: /* bkpt */ - { - int imm8 = extract32(insn, 0, 8); - ARCH(5); - gen_exception_bkpt_insn(s, syn_aa32_bkpt(imm8, true)); - break; - } - - case 0xa: /* rev, and hlt */ - { - int op1 = extract32(insn, 6, 2); - - if (op1 == 2) { - /* HLT */ - int imm6 = extract32(insn, 0, 6); - - gen_hlt(s, imm6); - break; - } - - /* Otherwise this is rev */ - ARCH(6); - rn = (insn >> 3) & 0x7; - rd = insn & 0x7; - tmp = load_reg(s, rn); - switch (op1) { - case 0: tcg_gen_bswap32_i32(tmp, tmp); break; - case 1: gen_rev16(tmp); break; - case 3: gen_revsh(tmp); break; - default: - g_assert_not_reached(); - } - store_reg(s, rd, tmp); - break; - } - - case 6: - switch ((insn >> 5) & 7) { - case 2: - /* setend */ - ARCH(6); - if (((insn >> 3) & 1) != !!(s->be_data == MO_BE)) { - gen_helper_setend(cpu_env); - s->base.is_jmp = DISAS_UPDATE; - } - break; - case 3: - /* cps */ - ARCH(6); - if (IS_USER(s)) { - break; - } - if (arm_dc_feature(s, ARM_FEATURE_M)) { - tmp = tcg_const_i32((insn & (1 << 4)) != 0); - /* FAULTMASK */ - if (insn & 1) { - addr = tcg_const_i32(19); - gen_helper_v7m_msr(cpu_env, addr, tmp); - tcg_temp_free_i32(addr); - } - /* PRIMASK */ - if (insn & 2) { - addr = tcg_const_i32(16); - gen_helper_v7m_msr(cpu_env, addr, tmp); - tcg_temp_free_i32(addr); - } - tcg_temp_free_i32(tmp); - gen_lookup_tb(s); - } else { - if (insn & (1 << 4)) { - shift = CPSR_A | CPSR_I | CPSR_F; - } else { - shift = 0; - } - gen_set_psr_im(s, ((insn & 7) << 6), 0, shift); - } - break; - default: - goto undef; - } - break; - - default: - goto undef; - } - break; - - case 12: - { - /* load/store multiple */ - TCGv_i32 loaded_var = NULL; - rn = (insn >> 8) & 0x7; - addr = load_reg(s, rn); - for (i = 0; i < 8; i++) { - if (insn & (1 << i)) { - if (insn & (1 << 11)) { - /* load */ - tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); - if (i == rn) { - loaded_var = tmp; - } else { - store_reg(s, i, tmp); - } - } else { - /* store */ - tmp = load_reg(s, i); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp); - } - /* advance to the next address */ - tcg_gen_addi_i32(addr, addr, 4); - } - } - if ((insn & (1 << rn)) == 0) { - /* base reg not in list: base register writeback */ - store_reg(s, rn, addr); - } else { - /* base reg in list: if load, complete it now */ - if (insn & (1 << 11)) { - store_reg(s, rn, loaded_var); - } - tcg_temp_free_i32(addr); - } - break; - } - case 13: - /* conditional branch or swi */ - cond = (insn >> 8) & 0xf; - if (cond == 0xe) - goto undef; - - if (cond == 0xf) { - /* swi */ - gen_set_pc_im(s, s->base.pc_next); - s->svc_imm = extract32(insn, 0, 8); - s->base.is_jmp = DISAS_SWI; - break; - } - /* generate a conditional jump to next instruction */ - arm_skip_unless(s, cond); - - /* jump to the offset */ - val = read_pc(s); - offset = ((int32_t)insn << 24) >> 24; - val += offset << 1; - gen_jmp(s, val); - break; - - case 14: - if (insn & (1 << 11)) { - /* thumb_insn_is_16bit() ensures we can't get here for - * a Thumb2 CPU, so this must be a thumb1 split BL/BLX: - * 0b1110_1xxx_xxxx_xxxx : BLX suffix (or UNDEF) - */ - assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2)); - ARCH(5); - offset = ((insn & 0x7ff) << 1); - tmp = load_reg(s, 14); - tcg_gen_addi_i32(tmp, tmp, offset); - tcg_gen_andi_i32(tmp, tmp, 0xfffffffc); - - tmp2 = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp2, s->base.pc_next | 1); - store_reg(s, 14, tmp2); - gen_bx(s, tmp); - break; - } - /* unconditional branch */ - val = read_pc(s); - offset = ((int32_t)insn << 21) >> 21; - val += offset << 1; - gen_jmp(s, val); - break; - - case 15: - /* thumb_insn_is_16bit() ensures we can't get here for - * a Thumb2 CPU, so this must be a thumb1 split BL/BLX. - */ - assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2)); - - if (insn & (1 << 11)) { - /* 0b1111_1xxx_xxxx_xxxx : BL suffix */ - offset = ((insn & 0x7ff) << 1) | 1; - tmp = load_reg(s, 14); - tcg_gen_addi_i32(tmp, tmp, offset); - - tmp2 = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp2, s->base.pc_next | 1); - store_reg(s, 14, tmp2); - gen_bx(s, tmp); - } else { - /* 0b1111_0xxx_xxxx_xxxx : BL/BLX prefix */ - uint32_t uoffset = ((int32_t)insn << 21) >> 9; - - tcg_gen_movi_i32(cpu_R[14], read_pc(s) + uoffset); - } - break; + if (!disas_t16(s, insn)) { + unallocated_encoding(s); } - return; -illegal_op: -undef: - unallocated_encoding(s); } static bool insn_crosses_page(CPUARMState *env, DisasContext *s) diff --git a/target/arm/translate.h b/target/arm/translate.h index 92ef790be9..dd24f91f26 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -23,7 +23,7 @@ typedef struct DisasContext { int condexec_cond; int thumb; int sctlr_b; - TCGMemOp be_data; + MemOp be_data; #if !defined(CONFIG_USER_ONLY) int user; #endif @@ -99,8 +99,6 @@ typedef struct DisasCompare { bool value_global; } DisasCompare; -void unallocated_encoding(DisasContext *s); - /* Share the TCG temporaries common between 32 and 64 bit modes. */ extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF; extern TCGv_i64 cpu_exclusive_addr; diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index df0f1361ef..f0516e81f1 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -137,9 +137,7 @@ static void do_stby_e(CPUHPPAState *env, target_ulong addr, target_ureg val, default: /* Nothing is stored, but protection is checked and the cacheline is marked dirty. */ -#ifndef CONFIG_USER_ONLY probe_write(env, addr, 0, cpu_mmu_index(env, 0), ra); -#endif break; } } diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 8c6189512c..53e17d8963 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -1500,7 +1500,7 @@ static void form_gva(DisasContext *ctx, TCGv_tl *pgva, TCGv_reg *pofs, */ static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, unsigned rx, int scale, target_sreg disp, - unsigned sp, int modify, TCGMemOp mop) + unsigned sp, int modify, MemOp mop) { TCGv_reg ofs; TCGv_tl addr; @@ -1518,7 +1518,7 @@ static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, unsigned rx, int scale, target_sreg disp, - unsigned sp, int modify, TCGMemOp mop) + unsigned sp, int modify, MemOp mop) { TCGv_reg ofs; TCGv_tl addr; @@ -1536,7 +1536,7 @@ static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, unsigned rx, int scale, target_sreg disp, - unsigned sp, int modify, TCGMemOp mop) + unsigned sp, int modify, MemOp mop) { TCGv_reg ofs; TCGv_tl addr; @@ -1554,7 +1554,7 @@ static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, unsigned rx, int scale, target_sreg disp, - unsigned sp, int modify, TCGMemOp mop) + unsigned sp, int modify, MemOp mop) { TCGv_reg ofs; TCGv_tl addr; @@ -1580,7 +1580,7 @@ static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, unsigned rx, int scale, target_sreg disp, - unsigned sp, int modify, TCGMemOp mop) + unsigned sp, int modify, MemOp mop) { TCGv_reg dest; @@ -1653,7 +1653,7 @@ static bool trans_fldd(DisasContext *ctx, arg_ldst *a) static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, target_sreg disp, unsigned sp, - int modify, TCGMemOp mop) + int modify, MemOp mop) { nullify_over(ctx); do_store_reg(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); @@ -2939,7 +2939,7 @@ static bool trans_st(DisasContext *ctx, arg_ldst *a) static bool trans_ldc(DisasContext *ctx, arg_ldst *a) { - TCGMemOp mop = MO_TEUL | MO_ALIGN_16 | a->size; + MemOp mop = MO_TEUL | MO_ALIGN_16 | a->size; TCGv_reg zero, dest, ofs; TCGv_tl addr; diff --git a/target/i386/translate.c b/target/i386/translate.c index 5cd74ad639..868b0acafe 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -87,8 +87,8 @@ typedef struct DisasContext { /* current insn context */ int override; /* -1 if no override */ int prefix; - TCGMemOp aflag; - TCGMemOp dflag; + MemOp aflag; + MemOp dflag; target_ulong pc_start; target_ulong pc; /* pc = eip + cs_base */ /* current block context */ @@ -149,7 +149,7 @@ static void gen_eob(DisasContext *s); static void gen_jr(DisasContext *s, TCGv dest); static void gen_jmp(DisasContext *s, target_ulong eip); static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num); -static void gen_op(DisasContext *s1, int op, TCGMemOp ot, int d); +static void gen_op(DisasContext *s1, int op, MemOp ot, int d); /* i386 arith/logic operations */ enum { @@ -320,7 +320,7 @@ static inline bool byte_reg_is_xH(DisasContext *s, int reg) } /* Select the size of a push/pop operation. */ -static inline TCGMemOp mo_pushpop(DisasContext *s, TCGMemOp ot) +static inline MemOp mo_pushpop(DisasContext *s, MemOp ot) { if (CODE64(s)) { return ot == MO_16 ? MO_16 : MO_64; @@ -330,13 +330,13 @@ static inline TCGMemOp mo_pushpop(DisasContext *s, TCGMemOp ot) } /* Select the size of the stack pointer. */ -static inline TCGMemOp mo_stacksize(DisasContext *s) +static inline MemOp mo_stacksize(DisasContext *s) { return CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16; } /* Select only size 64 else 32. Used for SSE operand sizes. */ -static inline TCGMemOp mo_64_32(TCGMemOp ot) +static inline MemOp mo_64_32(MemOp ot) { #ifdef TARGET_X86_64 return ot == MO_64 ? MO_64 : MO_32; @@ -347,19 +347,19 @@ static inline TCGMemOp mo_64_32(TCGMemOp ot) /* Select size 8 if lsb of B is clear, else OT. Used for decoding byte vs word opcodes. */ -static inline TCGMemOp mo_b_d(int b, TCGMemOp ot) +static inline MemOp mo_b_d(int b, MemOp ot) { return b & 1 ? ot : MO_8; } /* Select size 8 if lsb of B is clear, else OT capped at 32. Used for decoding operand size of port opcodes. */ -static inline TCGMemOp mo_b_d32(int b, TCGMemOp ot) +static inline MemOp mo_b_d32(int b, MemOp ot) { return b & 1 ? (ot == MO_16 ? MO_16 : MO_32) : MO_8; } -static void gen_op_mov_reg_v(DisasContext *s, TCGMemOp ot, int reg, TCGv t0) +static void gen_op_mov_reg_v(DisasContext *s, MemOp ot, int reg, TCGv t0) { switch(ot) { case MO_8: @@ -388,7 +388,7 @@ static void gen_op_mov_reg_v(DisasContext *s, TCGMemOp ot, int reg, TCGv t0) } static inline -void gen_op_mov_v_reg(DisasContext *s, TCGMemOp ot, TCGv t0, int reg) +void gen_op_mov_v_reg(DisasContext *s, MemOp ot, TCGv t0, int reg) { if (ot == MO_8 && byte_reg_is_xH(s, reg)) { tcg_gen_extract_tl(t0, cpu_regs[reg - 4], 8, 8); @@ -411,13 +411,13 @@ static inline void gen_op_jmp_v(TCGv dest) } static inline -void gen_op_add_reg_im(DisasContext *s, TCGMemOp size, int reg, int32_t val) +void gen_op_add_reg_im(DisasContext *s, MemOp size, int reg, int32_t val) { tcg_gen_addi_tl(s->tmp0, cpu_regs[reg], val); gen_op_mov_reg_v(s, size, reg, s->tmp0); } -static inline void gen_op_add_reg_T0(DisasContext *s, TCGMemOp size, int reg) +static inline void gen_op_add_reg_T0(DisasContext *s, MemOp size, int reg) { tcg_gen_add_tl(s->tmp0, cpu_regs[reg], s->T0); gen_op_mov_reg_v(s, size, reg, s->tmp0); @@ -451,7 +451,7 @@ static inline void gen_jmp_im(DisasContext *s, target_ulong pc) /* Compute SEG:REG into A0. SEG is selected from the override segment (OVR_SEG) and the default segment (DEF_SEG). OVR_SEG may be -1 to indicate no override. */ -static void gen_lea_v_seg(DisasContext *s, TCGMemOp aflag, TCGv a0, +static void gen_lea_v_seg(DisasContext *s, MemOp aflag, TCGv a0, int def_seg, int ovr_seg) { switch (aflag) { @@ -514,13 +514,13 @@ static inline void gen_string_movl_A0_EDI(DisasContext *s) gen_lea_v_seg(s, s->aflag, cpu_regs[R_EDI], R_ES, -1); } -static inline void gen_op_movl_T0_Dshift(DisasContext *s, TCGMemOp ot) +static inline void gen_op_movl_T0_Dshift(DisasContext *s, MemOp ot) { tcg_gen_ld32s_tl(s->T0, cpu_env, offsetof(CPUX86State, df)); tcg_gen_shli_tl(s->T0, s->T0, ot); }; -static TCGv gen_ext_tl(TCGv dst, TCGv src, TCGMemOp size, bool sign) +static TCGv gen_ext_tl(TCGv dst, TCGv src, MemOp size, bool sign) { switch (size) { case MO_8: @@ -551,18 +551,18 @@ static TCGv gen_ext_tl(TCGv dst, TCGv src, TCGMemOp size, bool sign) } } -static void gen_extu(TCGMemOp ot, TCGv reg) +static void gen_extu(MemOp ot, TCGv reg) { gen_ext_tl(reg, reg, ot, false); } -static void gen_exts(TCGMemOp ot, TCGv reg) +static void gen_exts(MemOp ot, TCGv reg) { gen_ext_tl(reg, reg, ot, true); } static inline -void gen_op_jnz_ecx(DisasContext *s, TCGMemOp size, TCGLabel *label1) +void gen_op_jnz_ecx(DisasContext *s, MemOp size, TCGLabel *label1) { tcg_gen_mov_tl(s->tmp0, cpu_regs[R_ECX]); gen_extu(size, s->tmp0); @@ -570,14 +570,14 @@ void gen_op_jnz_ecx(DisasContext *s, TCGMemOp size, TCGLabel *label1) } static inline -void gen_op_jz_ecx(DisasContext *s, TCGMemOp size, TCGLabel *label1) +void gen_op_jz_ecx(DisasContext *s, MemOp size, TCGLabel *label1) { tcg_gen_mov_tl(s->tmp0, cpu_regs[R_ECX]); gen_extu(size, s->tmp0); tcg_gen_brcondi_tl(TCG_COND_EQ, s->tmp0, 0, label1); } -static void gen_helper_in_func(TCGMemOp ot, TCGv v, TCGv_i32 n) +static void gen_helper_in_func(MemOp ot, TCGv v, TCGv_i32 n) { switch (ot) { case MO_8: @@ -594,7 +594,7 @@ static void gen_helper_in_func(TCGMemOp ot, TCGv v, TCGv_i32 n) } } -static void gen_helper_out_func(TCGMemOp ot, TCGv_i32 v, TCGv_i32 n) +static void gen_helper_out_func(MemOp ot, TCGv_i32 v, TCGv_i32 n) { switch (ot) { case MO_8: @@ -611,7 +611,7 @@ static void gen_helper_out_func(TCGMemOp ot, TCGv_i32 v, TCGv_i32 n) } } -static void gen_check_io(DisasContext *s, TCGMemOp ot, target_ulong cur_eip, +static void gen_check_io(DisasContext *s, MemOp ot, target_ulong cur_eip, uint32_t svm_flags) { target_ulong next_eip; @@ -644,7 +644,7 @@ static void gen_check_io(DisasContext *s, TCGMemOp ot, target_ulong cur_eip, } } -static inline void gen_movs(DisasContext *s, TCGMemOp ot) +static inline void gen_movs(DisasContext *s, MemOp ot) { gen_string_movl_A0_ESI(s); gen_op_ld_v(s, ot, s->T0, s->A0); @@ -840,7 +840,7 @@ static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg) return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 }; default: { - TCGMemOp size = (s->cc_op - CC_OP_ADDB) & 3; + MemOp size = (s->cc_op - CC_OP_ADDB) & 3; TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, true); return (CCPrepare) { .cond = TCG_COND_LT, .reg = t0, .mask = -1 }; } @@ -885,7 +885,7 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg) .mask = -1 }; default: { - TCGMemOp size = (s->cc_op - CC_OP_ADDB) & 3; + MemOp size = (s->cc_op - CC_OP_ADDB) & 3; TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, false); return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 }; } @@ -897,7 +897,7 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg) static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) { int inv, jcc_op, cond; - TCGMemOp size; + MemOp size; CCPrepare cc; TCGv t0; @@ -1075,7 +1075,7 @@ static TCGLabel *gen_jz_ecx_string(DisasContext *s, target_ulong next_eip) return l2; } -static inline void gen_stos(DisasContext *s, TCGMemOp ot) +static inline void gen_stos(DisasContext *s, MemOp ot) { gen_op_mov_v_reg(s, MO_32, s->T0, R_EAX); gen_string_movl_A0_EDI(s); @@ -1084,7 +1084,7 @@ static inline void gen_stos(DisasContext *s, TCGMemOp ot) gen_op_add_reg_T0(s, s->aflag, R_EDI); } -static inline void gen_lods(DisasContext *s, TCGMemOp ot) +static inline void gen_lods(DisasContext *s, MemOp ot) { gen_string_movl_A0_ESI(s); gen_op_ld_v(s, ot, s->T0, s->A0); @@ -1093,7 +1093,7 @@ static inline void gen_lods(DisasContext *s, TCGMemOp ot) gen_op_add_reg_T0(s, s->aflag, R_ESI); } -static inline void gen_scas(DisasContext *s, TCGMemOp ot) +static inline void gen_scas(DisasContext *s, MemOp ot) { gen_string_movl_A0_EDI(s); gen_op_ld_v(s, ot, s->T1, s->A0); @@ -1102,7 +1102,7 @@ static inline void gen_scas(DisasContext *s, TCGMemOp ot) gen_op_add_reg_T0(s, s->aflag, R_EDI); } -static inline void gen_cmps(DisasContext *s, TCGMemOp ot) +static inline void gen_cmps(DisasContext *s, MemOp ot) { gen_string_movl_A0_EDI(s); gen_op_ld_v(s, ot, s->T1, s->A0); @@ -1126,7 +1126,7 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot) } -static inline void gen_ins(DisasContext *s, TCGMemOp ot) +static inline void gen_ins(DisasContext *s, MemOp ot) { if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); @@ -1148,7 +1148,7 @@ static inline void gen_ins(DisasContext *s, TCGMemOp ot) } } -static inline void gen_outs(DisasContext *s, TCGMemOp ot) +static inline void gen_outs(DisasContext *s, MemOp ot) { if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); @@ -1171,7 +1171,7 @@ static inline void gen_outs(DisasContext *s, TCGMemOp ot) /* same method as Valgrind : we generate jumps to current or next instruction */ #define GEN_REPZ(op) \ -static inline void gen_repz_ ## op(DisasContext *s, TCGMemOp ot, \ +static inline void gen_repz_ ## op(DisasContext *s, MemOp ot, \ target_ulong cur_eip, target_ulong next_eip) \ { \ TCGLabel *l2; \ @@ -1187,7 +1187,7 @@ static inline void gen_repz_ ## op(DisasContext *s, TCGMemOp ot, \ } #define GEN_REPZ2(op) \ -static inline void gen_repz_ ## op(DisasContext *s, TCGMemOp ot, \ +static inline void gen_repz_ ## op(DisasContext *s, MemOp ot, \ target_ulong cur_eip, \ target_ulong next_eip, \ int nz) \ @@ -1284,7 +1284,7 @@ static void gen_illegal_opcode(DisasContext *s) } /* if d == OR_TMP0, it means memory operand (address in A0) */ -static void gen_op(DisasContext *s1, int op, TCGMemOp ot, int d) +static void gen_op(DisasContext *s1, int op, MemOp ot, int d) { if (d != OR_TMP0) { if (s1->prefix & PREFIX_LOCK) { @@ -1395,7 +1395,7 @@ static void gen_op(DisasContext *s1, int op, TCGMemOp ot, int d) } /* if d == OR_TMP0, it means memory operand (address in A0) */ -static void gen_inc(DisasContext *s1, TCGMemOp ot, int d, int c) +static void gen_inc(DisasContext *s1, MemOp ot, int d, int c) { if (s1->prefix & PREFIX_LOCK) { if (d != OR_TMP0) { @@ -1421,7 +1421,7 @@ static void gen_inc(DisasContext *s1, TCGMemOp ot, int d, int c) set_cc_op(s1, (c > 0 ? CC_OP_INCB : CC_OP_DECB) + ot); } -static void gen_shift_flags(DisasContext *s, TCGMemOp ot, TCGv result, +static void gen_shift_flags(DisasContext *s, MemOp ot, TCGv result, TCGv shm1, TCGv count, bool is_right) { TCGv_i32 z32, s32, oldop; @@ -1466,7 +1466,7 @@ static void gen_shift_flags(DisasContext *s, TCGMemOp ot, TCGv result, set_cc_op(s, CC_OP_DYNAMIC); } -static void gen_shift_rm_T1(DisasContext *s, TCGMemOp ot, int op1, +static void gen_shift_rm_T1(DisasContext *s, MemOp ot, int op1, int is_right, int is_arith) { target_ulong mask = (ot == MO_64 ? 0x3f : 0x1f); @@ -1502,7 +1502,7 @@ static void gen_shift_rm_T1(DisasContext *s, TCGMemOp ot, int op1, gen_shift_flags(s, ot, s->T0, s->tmp0, s->T1, is_right); } -static void gen_shift_rm_im(DisasContext *s, TCGMemOp ot, int op1, int op2, +static void gen_shift_rm_im(DisasContext *s, MemOp ot, int op1, int op2, int is_right, int is_arith) { int mask = (ot == MO_64 ? 0x3f : 0x1f); @@ -1542,7 +1542,7 @@ static void gen_shift_rm_im(DisasContext *s, TCGMemOp ot, int op1, int op2, } } -static void gen_rot_rm_T1(DisasContext *s, TCGMemOp ot, int op1, int is_right) +static void gen_rot_rm_T1(DisasContext *s, MemOp ot, int op1, int is_right) { target_ulong mask = (ot == MO_64 ? 0x3f : 0x1f); TCGv_i32 t0, t1; @@ -1627,7 +1627,7 @@ static void gen_rot_rm_T1(DisasContext *s, TCGMemOp ot, int op1, int is_right) set_cc_op(s, CC_OP_DYNAMIC); } -static void gen_rot_rm_im(DisasContext *s, TCGMemOp ot, int op1, int op2, +static void gen_rot_rm_im(DisasContext *s, MemOp ot, int op1, int op2, int is_right) { int mask = (ot == MO_64 ? 0x3f : 0x1f); @@ -1705,7 +1705,7 @@ static void gen_rot_rm_im(DisasContext *s, TCGMemOp ot, int op1, int op2, } /* XXX: add faster immediate = 1 case */ -static void gen_rotc_rm_T1(DisasContext *s, TCGMemOp ot, int op1, +static void gen_rotc_rm_T1(DisasContext *s, MemOp ot, int op1, int is_right) { gen_compute_eflags(s); @@ -1761,7 +1761,7 @@ static void gen_rotc_rm_T1(DisasContext *s, TCGMemOp ot, int op1, } /* XXX: add faster immediate case */ -static void gen_shiftd_rm_T1(DisasContext *s, TCGMemOp ot, int op1, +static void gen_shiftd_rm_T1(DisasContext *s, MemOp ot, int op1, bool is_right, TCGv count_in) { target_ulong mask = (ot == MO_64 ? 63 : 31); @@ -1842,7 +1842,7 @@ static void gen_shiftd_rm_T1(DisasContext *s, TCGMemOp ot, int op1, tcg_temp_free(count); } -static void gen_shift(DisasContext *s1, int op, TCGMemOp ot, int d, int s) +static void gen_shift(DisasContext *s1, int op, MemOp ot, int d, int s) { if (s != OR_TMP1) gen_op_mov_v_reg(s1, ot, s1->T1, s); @@ -1872,7 +1872,7 @@ static void gen_shift(DisasContext *s1, int op, TCGMemOp ot, int d, int s) } } -static void gen_shifti(DisasContext *s1, int op, TCGMemOp ot, int d, int c) +static void gen_shifti(DisasContext *s1, int op, MemOp ot, int d, int c) { switch(op) { case OP_ROL: @@ -2149,7 +2149,7 @@ static void gen_add_A0_ds_seg(DisasContext *s) /* generate modrm memory load or store of 'reg'. TMP0 is used if reg == OR_TMP0 */ static void gen_ldst_modrm(CPUX86State *env, DisasContext *s, int modrm, - TCGMemOp ot, int reg, int is_store) + MemOp ot, int reg, int is_store) { int mod, rm; @@ -2179,7 +2179,7 @@ static void gen_ldst_modrm(CPUX86State *env, DisasContext *s, int modrm, } } -static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, TCGMemOp ot) +static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, MemOp ot) { uint32_t ret; @@ -2202,7 +2202,7 @@ static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, TCGMemOp ot) return ret; } -static inline int insn_const_size(TCGMemOp ot) +static inline int insn_const_size(MemOp ot) { if (ot <= MO_32) { return 1 << ot; @@ -2266,7 +2266,7 @@ static inline void gen_jcc(DisasContext *s, int b, } } -static void gen_cmovcc1(CPUX86State *env, DisasContext *s, TCGMemOp ot, int b, +static void gen_cmovcc1(CPUX86State *env, DisasContext *s, MemOp ot, int b, int modrm, int reg) { CCPrepare cc; @@ -2363,8 +2363,8 @@ static inline void gen_stack_update(DisasContext *s, int addend) /* Generate a push. It depends on ss32, addseg and dflag. */ static void gen_push_v(DisasContext *s, TCGv val) { - TCGMemOp d_ot = mo_pushpop(s, s->dflag); - TCGMemOp a_ot = mo_stacksize(s); + MemOp d_ot = mo_pushpop(s, s->dflag); + MemOp a_ot = mo_stacksize(s); int size = 1 << d_ot; TCGv new_esp = s->A0; @@ -2383,9 +2383,9 @@ static void gen_push_v(DisasContext *s, TCGv val) } /* two step pop is necessary for precise exceptions */ -static TCGMemOp gen_pop_T0(DisasContext *s) +static MemOp gen_pop_T0(DisasContext *s) { - TCGMemOp d_ot = mo_pushpop(s, s->dflag); + MemOp d_ot = mo_pushpop(s, s->dflag); gen_lea_v_seg(s, mo_stacksize(s), cpu_regs[R_ESP], R_SS, -1); gen_op_ld_v(s, d_ot, s->T0, s->A0); @@ -2393,7 +2393,7 @@ static TCGMemOp gen_pop_T0(DisasContext *s) return d_ot; } -static inline void gen_pop_update(DisasContext *s, TCGMemOp ot) +static inline void gen_pop_update(DisasContext *s, MemOp ot) { gen_stack_update(s, 1 << ot); } @@ -2405,8 +2405,8 @@ static inline void gen_stack_A0(DisasContext *s) static void gen_pusha(DisasContext *s) { - TCGMemOp s_ot = s->ss32 ? MO_32 : MO_16; - TCGMemOp d_ot = s->dflag; + MemOp s_ot = s->ss32 ? MO_32 : MO_16; + MemOp d_ot = s->dflag; int size = 1 << d_ot; int i; @@ -2421,8 +2421,8 @@ static void gen_pusha(DisasContext *s) static void gen_popa(DisasContext *s) { - TCGMemOp s_ot = s->ss32 ? MO_32 : MO_16; - TCGMemOp d_ot = s->dflag; + MemOp s_ot = s->ss32 ? MO_32 : MO_16; + MemOp d_ot = s->dflag; int size = 1 << d_ot; int i; @@ -2442,8 +2442,8 @@ static void gen_popa(DisasContext *s) static void gen_enter(DisasContext *s, int esp_addend, int level) { - TCGMemOp d_ot = mo_pushpop(s, s->dflag); - TCGMemOp a_ot = CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16; + MemOp d_ot = mo_pushpop(s, s->dflag); + MemOp a_ot = CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16; int size = 1 << d_ot; /* Push BP; compute FrameTemp into T1. */ @@ -2482,8 +2482,8 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) static void gen_leave(DisasContext *s) { - TCGMemOp d_ot = mo_pushpop(s, s->dflag); - TCGMemOp a_ot = mo_stacksize(s); + MemOp d_ot = mo_pushpop(s, s->dflag); + MemOp a_ot = mo_stacksize(s); gen_lea_v_seg(s, a_ot, cpu_regs[R_EBP], R_SS, -1); gen_op_ld_v(s, d_ot, s->T0, s->A0); @@ -3045,7 +3045,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, SSEFunc_0_eppi sse_fn_eppi; SSEFunc_0_ppi sse_fn_ppi; SSEFunc_0_eppt sse_fn_eppt; - TCGMemOp ot; + MemOp ot; b &= 0xff; if (s->prefix & PREFIX_DATA) @@ -4488,7 +4488,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) CPUX86State *env = cpu->env_ptr; int b, prefixes; int shift; - TCGMemOp ot, aflag, dflag; + MemOp ot, aflag, dflag; int modrm, reg, rm, mod, op, opreg, val; target_ulong next_eip, tval; int rex_w, rex_r; @@ -5566,8 +5566,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x1be: /* movsbS Gv, Eb */ case 0x1bf: /* movswS Gv, Eb */ { - TCGMemOp d_ot; - TCGMemOp s_ot; + MemOp d_ot; + MemOp s_ot; /* d_ot is the size of destination */ d_ot = dflag; diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 60bcfb7bd0..24c1dd3408 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -2414,7 +2414,7 @@ DISAS_INSN(cas) uint16_t ext; TCGv load; TCGv cmp; - TCGMemOp opc; + MemOp opc; switch ((insn >> 9) & 3) { case 1: diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 95ff663292..761f535357 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -919,7 +919,7 @@ static void dec_load(DisasContext *dc) unsigned int size; bool rev = false, ex = false, ea = false; int mem_index = cpu_mmu_index(&dc->cpu->env, false); - TCGMemOp mop; + MemOp mop; mop = dc->opcode & 3; size = 1 << mop; @@ -1035,7 +1035,7 @@ static void dec_store(DisasContext *dc) unsigned int size; bool rev = false, ex = false, ea = false; int mem_index = cpu_mmu_index(&dc->cpu->env, false); - TCGMemOp mop; + MemOp mop; mop = dc->opcode & 3; size = 1 << mop; diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 1fd4a180e1..ca00f41daf 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -192,14 +192,14 @@ typedef struct mips_def_t mips_def_t; * Register 16 Register 17 Register 18 Register 19 * ----------- ----------- ----------- ----------- * - * 0 Config LLAddr WatchLo WatchHi - * 1 Config1 MAAR WatchLo WatchHi - * 2 Config2 MAARI WatchLo WatchHi - * 3 Config3 WatchLo WatchHi - * 4 Config4 WatchLo WatchHi - * 5 Config5 WatchLo WatchHi - * 6 WatchLo WatchHi - * 7 WatchLo WatchHi + * 0 Config LLAddr WatchLo0 WatchHi + * 1 Config1 MAAR WatchLo1 WatchHi + * 2 Config2 MAARI WatchLo2 WatchHi + * 3 Config3 WatchLo3 WatchHi + * 4 Config4 WatchLo4 WatchHi + * 5 Config5 WatchLo5 WatchHi + * 6 WatchLo6 WatchHi + * 7 WatchLo7 WatchHi * * * Register 20 Register 21 Register 22 Register 23 @@ -233,12 +233,12 @@ typedef struct mips_def_t mips_def_t; * * 0 DataLo DataHi ErrorEPC DESAVE * 1 TagLo TagHi - * 2 DataLo DataHi KScratch<n> - * 3 TagLo TagHi KScratch<n> - * 4 DataLo DataHi KScratch<n> - * 5 TagLo TagHi KScratch<n> - * 6 DataLo DataHi KScratch<n> - * 7 TagLo TagHi KScratch<n> + * 2 DataLo1 DataHi1 KScratch<n> + * 3 TagLo1 TagHi1 KScratch<n> + * 4 DataLo2 DataHi2 KScratch<n> + * 5 TagLo2 TagHi2 KScratch<n> + * 6 DataLo3 DataHi3 KScratch<n> + * 7 TagLo3 TagHi3 KScratch<n> * */ #define CP0_REGISTER_00 0 @@ -277,29 +277,63 @@ typedef struct mips_def_t mips_def_t; /* CP0 Register 00 */ #define CP0_REG00__INDEX 0 +#define CP0_REG00__MVPCONTROL 1 +#define CP0_REG00__MVPCONF0 2 +#define CP0_REG00__MVPCONF1 3 #define CP0_REG00__VPCONTROL 4 /* CP0 Register 01 */ +#define CP0_REG01__RANDOM 0 +#define CP0_REG01__VPECONTROL 1 +#define CP0_REG01__VPECONF0 2 +#define CP0_REG01__VPECONF1 3 +#define CP0_REG01__YQMASK 4 +#define CP0_REG01__VPESCHEDULE 5 +#define CP0_REG01__VPESCHEFBACK 6 +#define CP0_REG01__VPEOPT 7 /* CP0 Register 02 */ #define CP0_REG02__ENTRYLO0 0 +#define CP0_REG02__TCSTATUS 1 +#define CP0_REG02__TCBIND 2 +#define CP0_REG02__TCRESTART 3 +#define CP0_REG02__TCHALT 4 +#define CP0_REG02__TCCONTEXT 5 +#define CP0_REG02__TCSCHEDULE 6 +#define CP0_REG02__TCSCHEFBACK 7 /* CP0 Register 03 */ #define CP0_REG03__ENTRYLO1 0 #define CP0_REG03__GLOBALNUM 1 +#define CP0_REG03__TCOPT 7 /* CP0 Register 04 */ #define CP0_REG04__CONTEXT 0 +#define CP0_REG04__CONTEXTCONFIG 1 #define CP0_REG04__USERLOCAL 2 +#define CP0_REG04__XCONTEXTCONFIG 3 #define CP0_REG04__DBGCONTEXTID 4 #define CP0_REG00__MMID 5 /* CP0 Register 05 */ #define CP0_REG05__PAGEMASK 0 #define CP0_REG05__PAGEGRAIN 1 +#define CP0_REG05__SEGCTL0 2 +#define CP0_REG05__SEGCTL1 3 +#define CP0_REG05__SEGCTL2 4 +#define CP0_REG05__PWBASE 5 +#define CP0_REG05__PWFIELD 6 +#define CP0_REG05__PWSIZE 7 /* CP0 Register 06 */ #define CP0_REG06__WIRED 0 +#define CP0_REG06__SRSCONF0 1 +#define CP0_REG06__SRSCONF1 2 +#define CP0_REG06__SRSCONF2 3 +#define CP0_REG06__SRSCONF3 4 +#define CP0_REG06__SRSCONF4 5 +#define CP0_REG06__PWCTL 6 /* CP0 Register 07 */ #define CP0_REG07__HWRENA 0 /* CP0 Register 08 */ #define CP0_REG08__BADVADDR 0 #define CP0_REG08__BADINSTR 1 #define CP0_REG08__BADINSTRP 2 +#define CP0_REG08__BADINSTRX 3 /* CP0 Register 09 */ #define CP0_REG09__COUNT 0 #define CP0_REG09__SAARI 6 @@ -308,6 +342,7 @@ typedef struct mips_def_t mips_def_t; #define CP0_REG10__ENTRYHI 0 #define CP0_REG10__GUESTCTL1 4 #define CP0_REG10__GUESTCTL2 5 +#define CP0_REG10__GUESTCTL3 6 /* CP0 Register 11 */ #define CP0_REG11__COMPARE 0 #define CP0_REG11__GUESTCTL0EXT 4 @@ -315,17 +350,24 @@ typedef struct mips_def_t mips_def_t; #define CP0_REG12__STATUS 0 #define CP0_REG12__INTCTL 1 #define CP0_REG12__SRSCTL 2 +#define CP0_REG12__SRSMAP 3 +#define CP0_REG12__VIEW_IPL 4 +#define CP0_REG12__SRSMAP2 5 #define CP0_REG12__GUESTCTL0 6 #define CP0_REG12__GTOFFSET 7 /* CP0 Register 13 */ #define CP0_REG13__CAUSE 0 +#define CP0_REG13__VIEW_RIPL 4 +#define CP0_REG13__NESTEDEXC 5 /* CP0 Register 14 */ #define CP0_REG14__EPC 0 +#define CP0_REG14__NESTEDEPC 2 /* CP0 Register 15 */ #define CP0_REG15__PRID 0 #define CP0_REG15__EBASE 1 #define CP0_REG15__CDMMBASE 2 #define CP0_REG15__CMGCRBASE 3 +#define CP0_REG15__BEVVA 4 /* CP0 Register 16 */ #define CP0_REG16__CONFIG 0 #define CP0_REG16__CONFIG1 1 @@ -333,7 +375,8 @@ typedef struct mips_def_t mips_def_t; #define CP0_REG16__CONFIG3 3 #define CP0_REG16__CONFIG4 4 #define CP0_REG16__CONFIG5 5 -#define CP0_REG00__CONFIG7 7 +#define CP0_REG16__CONFIG6 6 +#define CP0_REG16__CONFIG7 7 /* CP0 Register 17 */ #define CP0_REG17__LLADDR 0 #define CP0_REG17__MAAR 1 @@ -343,17 +386,31 @@ typedef struct mips_def_t mips_def_t; #define CP0_REG18__WATCHLO1 1 #define CP0_REG18__WATCHLO2 2 #define CP0_REG18__WATCHLO3 3 +#define CP0_REG18__WATCHLO4 4 +#define CP0_REG18__WATCHLO5 5 +#define CP0_REG18__WATCHLO6 6 +#define CP0_REG18__WATCHLO7 7 /* CP0 Register 19 */ #define CP0_REG19__WATCHHI0 0 #define CP0_REG19__WATCHHI1 1 #define CP0_REG19__WATCHHI2 2 #define CP0_REG19__WATCHHI3 3 +#define CP0_REG19__WATCHHI4 4 +#define CP0_REG19__WATCHHI5 5 +#define CP0_REG19__WATCHHI6 6 +#define CP0_REG19__WATCHHI7 7 /* CP0 Register 20 */ #define CP0_REG20__XCONTEXT 0 /* CP0 Register 21 */ /* CP0 Register 22 */ /* CP0 Register 23 */ #define CP0_REG23__DEBUG 0 +#define CP0_REG23__TRACECONTROL 1 +#define CP0_REG23__TRACECONTROL2 2 +#define CP0_REG23__USERTRACEDATA1 3 +#define CP0_REG23__TRACEIBPC 4 +#define CP0_REG23__TRACEDBPC 5 +#define CP0_REG23__DEBUG2 6 /* CP0 Register 24 */ #define CP0_REG24__DEPC 0 /* CP0 Register 25 */ @@ -366,17 +423,27 @@ typedef struct mips_def_t mips_def_t; #define CP0_REG25__PERFCTL3 6 #define CP0_REG25__PERFCNT3 7 /* CP0 Register 26 */ -#define CP0_REG00__ERRCTL 0 +#define CP0_REG26__ERRCTL 0 /* CP0 Register 27 */ #define CP0_REG27__CACHERR 0 /* CP0 Register 28 */ -#define CP0_REG28__ITAGLO 0 -#define CP0_REG28__IDATALO 1 -#define CP0_REG28__DTAGLO 2 -#define CP0_REG28__DDATALO 3 +#define CP0_REG28__TAGLO 0 +#define CP0_REG28__DATALO 1 +#define CP0_REG28__TAGLO1 2 +#define CP0_REG28__DATALO1 3 +#define CP0_REG28__TAGLO2 4 +#define CP0_REG28__DATALO2 5 +#define CP0_REG28__TAGLO3 6 +#define CP0_REG28__DATALO3 7 /* CP0 Register 29 */ -#define CP0_REG29__IDATAHI 1 -#define CP0_REG29__DDATAHI 3 +#define CP0_REG29__TAGHI 0 +#define CP0_REG29__DATAHI 1 +#define CP0_REG29__TAGHI1 2 +#define CP0_REG29__DATAHI1 3 +#define CP0_REG29__TAGHI2 4 +#define CP0_REG29__DATAHI2 5 +#define CP0_REG29__TAGHI3 6 +#define CP0_REG29__DATAHI3 7 /* CP0 Register 30 */ #define CP0_REG30__ERROREPC 0 /* CP0 Register 31 */ @@ -546,7 +613,6 @@ struct CPUMIPSState { * CP0 Register 4 */ target_ulong CP0_Context; - target_ulong CP0_KScratch[MIPS_KSCRATCH_NUM]; int32_t CP0_MemoryMapID; /* * CP0 Register 5 @@ -957,6 +1023,7 @@ struct CPUMIPSState { * CP0 Register 31 */ int32_t CP0_DESAVE; + target_ulong CP0_KScratch[MIPS_KSCRATCH_NUM]; /* We waste some space so we can handle shadow registers like TCs. */ TCState tcs[MIPS_SHADOW_SET_MAX]; diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index f88a3ab904..01b9e78bf3 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -24,6 +24,7 @@ #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" +#include "exec/memop.h" #include "sysemu/kvm.h" #include "fpu/softfloat.h" @@ -4536,16 +4537,14 @@ static inline void ensure_writable_pages(CPUMIPSState *env, int mmu_idx, uintptr_t retaddr) { -#if !defined(CONFIG_USER_ONLY) - target_ulong page_addr; + /* FIXME: Probe the actual accesses (pass and use a size) */ if (unlikely(MSA_PAGESPAN(addr))) { /* first page */ probe_write(env, addr, 0, mmu_idx, retaddr); /* second page */ - page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; - probe_write(env, page_addr, 0, mmu_idx, retaddr); + addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + probe_write(env, addr, 0, mmu_idx, retaddr); } -#endif } void helper_msa_st_b(CPUMIPSState *env, uint32_t wd, @@ -4692,15 +4691,15 @@ void helper_msa_st_w(CPUMIPSState *env, uint32_t wd, ensure_writable_pages(env, addr, mmu_idx, GETPC()); #if !defined(CONFIG_USER_ONLY) #if !defined(HOST_WORDS_BIGENDIAN) - helper_ret_stl_mmu(env, addr + (0 << DF_WORD), oi, GETPC(), pwd->w[0]); - helper_ret_stl_mmu(env, addr + (1 << DF_WORD), oi, GETPC(), pwd->w[1]); - helper_ret_stl_mmu(env, addr + (2 << DF_WORD), oi, GETPC(), pwd->w[2]); - helper_ret_stl_mmu(env, addr + (3 << DF_WORD), oi, GETPC(), pwd->w[3]); + helper_ret_stl_mmu(env, addr + (0 << DF_WORD), pwd->w[0], oi, GETPC()); + helper_ret_stl_mmu(env, addr + (1 << DF_WORD), pwd->w[1], oi, GETPC()); + helper_ret_stl_mmu(env, addr + (2 << DF_WORD), pwd->w[2], oi, GETPC()); + helper_ret_stl_mmu(env, addr + (3 << DF_WORD), pwd->w[3], oi, GETPC()); #else - helper_ret_stl_mmu(env, addr + (1 << DF_WORD), oi, GETPC(), pwd->w[0]); - helper_ret_stl_mmu(env, addr + (0 << DF_WORD), oi, GETPC(), pwd->w[1]); - helper_ret_stl_mmu(env, addr + (3 << DF_WORD), oi, GETPC(), pwd->w[2]); - helper_ret_stl_mmu(env, addr + (2 << DF_WORD), oi, GETPC(), pwd->w[3]); + helper_ret_stl_mmu(env, addr + (1 << DF_WORD), pwd->w[0], oi, GETPC()); + helper_ret_stl_mmu(env, addr + (0 << DF_WORD), pwd->w[1], oi, GETPC()); + helper_ret_stl_mmu(env, addr + (3 << DF_WORD), pwd->w[2], oi, GETPC()); + helper_ret_stl_mmu(env, addr + (2 << DF_WORD), pwd->w[3], oi, GETPC()); #endif #else #if !defined(HOST_WORDS_BIGENDIAN) @@ -4741,11 +4740,11 @@ void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op) if (op == 9) { /* Index Store Tag */ memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo, - 8, MEMTXATTRS_UNSPECIFIED); + MO_64, MEMTXATTRS_UNSPECIFIED); } else if (op == 5) { /* Index Load Tag */ memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo, - 8, MEMTXATTRS_UNSPECIFIED); + MO_64, MEMTXATTRS_UNSPECIFIED); } #endif } diff --git a/target/mips/translate.c b/target/mips/translate.c index 8ebde6ffee..f2119955cf 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -2526,7 +2526,7 @@ typedef struct DisasContext { int32_t CP0_Config5; /* Routine used to access memory */ int mem_idx; - TCGMemOp default_tcg_memop_mask; + MemOp default_tcg_memop_mask; uint32_t hflags, saved_hflags; target_ulong btarget; bool ulri; @@ -3706,7 +3706,7 @@ static void gen_st(DisasContext *ctx, uint32_t opc, int rt, /* Store conditional */ static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset, - TCGMemOp tcg_mo, bool eva) + MemOp tcg_mo, bool eva) { TCGv addr, t0, val; TCGLabel *l1 = gen_new_label(); @@ -4549,7 +4549,7 @@ static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg) } static inline void gen_r6_ld(target_long addr, int reg, int memidx, - TCGMemOp memop) + MemOp memop) { TCGv t0 = tcg_const_tl(addr); tcg_gen_qemu_ld_tl(t0, t0, memidx, memop); @@ -6647,7 +6647,7 @@ static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_03: switch (sel) { - case 0: + case CP0_REG03__ENTRYLO1: CP0_CHECK(ctx->hflags & MIPS_HFLAG_ELPA); gen_mfhc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1)); register_name = "EntryLo1"; @@ -6658,7 +6658,7 @@ static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_09: switch (sel) { - case 7: + case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); gen_helper_mfhc0_saar(arg, cpu_env); register_name = "SAAR"; @@ -6669,12 +6669,12 @@ static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_17: switch (sel) { - case 0: + case CP0_REG17__LLADDR: gen_mfhc0_load64(arg, offsetof(CPUMIPSState, CP0_LLAddr), ctx->CP0_LLAddr_shift); register_name = "LLAddr"; break; - case 1: + case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); gen_helper_mfhc0_maar(arg, cpu_env); register_name = "MAAR"; @@ -6728,7 +6728,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_03: switch (sel) { - case 0: + case CP0_REG03__ENTRYLO1: CP0_CHECK(ctx->hflags & MIPS_HFLAG_ELPA); tcg_gen_andi_tl(arg, arg, mask); gen_mthc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1)); @@ -6740,7 +6740,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_09: switch (sel) { - case 7: + case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); gen_helper_mthc0_saar(cpu_env, arg); register_name = "SAAR"; @@ -6751,7 +6751,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_17: switch (sel) { - case 0: + case CP0_REG17__LLADDR: /* * LLAddr is read-only (the only exception is bit 0 if LLB is * supported); the CP0_LLAddr_rw_bitmask does not seem to be @@ -6760,7 +6760,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel) */ register_name = "LLAddr"; break; - case 1: + case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); gen_helper_mthc0_maar(cpu_env, arg); register_name = "MAAR"; @@ -6813,26 +6813,26 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (reg) { case CP0_REGISTER_00: switch (sel) { - case 0: + case CP0_REG00__INDEX: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Index)); register_name = "Index"; break; - case 1: + case CP0_REG00__MVPCONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpcontrol(arg, cpu_env); register_name = "MVPControl"; break; - case 2: + case CP0_REG00__MVPCONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpconf0(arg, cpu_env); register_name = "MVPConf0"; break; - case 3: + case CP0_REG00__MVPCONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpconf1(arg, cpu_env); register_name = "MVPConf1"; break; - case 4: + case CP0_REG00__VPCONTROL: CP0_CHECK(ctx->vp); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPControl)); register_name = "VPControl"; @@ -6843,42 +6843,42 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_01: switch (sel) { - case 0: + case CP0_REG01__RANDOM: CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6)); gen_helper_mfc0_random(arg, cpu_env); register_name = "Random"; break; - case 1: + case CP0_REG01__VPECONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl)); register_name = "VPEControl"; break; - case 2: + case CP0_REG01__VPECONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0)); register_name = "VPEConf0"; break; - case 3: + case CP0_REG01__VPECONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1)); register_name = "VPEConf1"; break; - case 4: + case CP0_REG01__YQMASK: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_YQMask)); register_name = "YQMask"; break; - case 5: + case CP0_REG01__VPESCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPESchedule)); register_name = "VPESchedule"; break; - case 6: + case CP0_REG01__VPESCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPEScheFBack)); register_name = "VPEScheFBack"; break; - case 7: + case CP0_REG01__VPEOPT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt)); register_name = "VPEOpt"; @@ -6889,7 +6889,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_02: switch (sel) { - case 0: + case CP0_REG02__ENTRYLO0: { TCGv_i64 tmp = tcg_temp_new_i64(); tcg_gen_ld_i64(tmp, cpu_env, @@ -6906,37 +6906,37 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) } register_name = "EntryLo0"; break; - case 1: + case CP0_REG02__TCSTATUS: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcstatus(arg, cpu_env); register_name = "TCStatus"; break; - case 2: + case CP0_REG02__TCBIND: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcbind(arg, cpu_env); register_name = "TCBind"; break; - case 3: + case CP0_REG02__TCRESTART: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcrestart(arg, cpu_env); register_name = "TCRestart"; break; - case 4: + case CP0_REG02__TCHALT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tchalt(arg, cpu_env); register_name = "TCHalt"; break; - case 5: + case CP0_REG02__TCCONTEXT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tccontext(arg, cpu_env); register_name = "TCContext"; break; - case 6: + case CP0_REG02__TCSCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcschedule(arg, cpu_env); register_name = "TCSchedule"; break; - case 7: + case CP0_REG02__TCSCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcschefback(arg, cpu_env); register_name = "TCScheFBack"; @@ -6947,7 +6947,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_03: switch (sel) { - case 0: + case CP0_REG03__ENTRYLO1: { TCGv_i64 tmp = tcg_temp_new_i64(); tcg_gen_ld_i64(tmp, cpu_env, @@ -6964,7 +6964,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) } register_name = "EntryLo1"; break; - case 1: + case CP0_REG03__GLOBALNUM: CP0_CHECK(ctx->vp); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_GlobalNumber)); register_name = "GlobalNumber"; @@ -6975,16 +6975,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_04: switch (sel) { - case 0: + case CP0_REG04__CONTEXT: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_Context)); tcg_gen_ext32s_tl(arg, arg); register_name = "Context"; break; - case 1: - /* gen_helper_mfc0_contextconfig(arg); - SmartMIPS ASE */ + case CP0_REG04__CONTEXTCONFIG: + /* SmartMIPS ASE */ + /* gen_helper_mfc0_contextconfig(arg); */ register_name = "ContextConfig"; goto cp0_unimplemented; - case 2: + case CP0_REG04__USERLOCAL: CP0_CHECK(ctx->ulri); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); @@ -6997,44 +6998,44 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_05: switch (sel) { - case 0: + case CP0_REG05__PAGEMASK: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageMask)); register_name = "PageMask"; break; - case 1: + case CP0_REG05__PAGEGRAIN: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain)); register_name = "PageGrain"; break; - case 2: + case CP0_REG05__SEGCTL0: CP0_CHECK(ctx->sc); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0)); tcg_gen_ext32s_tl(arg, arg); register_name = "SegCtl0"; break; - case 3: + case CP0_REG05__SEGCTL1: CP0_CHECK(ctx->sc); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1)); tcg_gen_ext32s_tl(arg, arg); register_name = "SegCtl1"; break; - case 4: + case CP0_REG05__SEGCTL2: CP0_CHECK(ctx->sc); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2)); tcg_gen_ext32s_tl(arg, arg); register_name = "SegCtl2"; break; - case 5: + case CP0_REG05__PWBASE: check_pw(ctx); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWBase)); register_name = "PWBase"; break; - case 6: + case CP0_REG05__PWFIELD: check_pw(ctx); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWField)); register_name = "PWField"; break; - case 7: + case CP0_REG05__PWSIZE: check_pw(ctx); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWSize)); register_name = "PWSize"; @@ -7045,36 +7046,36 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_06: switch (sel) { - case 0: + case CP0_REG06__WIRED: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Wired)); register_name = "Wired"; break; - case 1: + case CP0_REG06__SRSCONF0: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf0)); register_name = "SRSConf0"; break; - case 2: + case CP0_REG06__SRSCONF1: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf1)); register_name = "SRSConf1"; break; - case 3: + case CP0_REG06__SRSCONF2: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf2)); register_name = "SRSConf2"; break; - case 4: + case CP0_REG06__SRSCONF3: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf3)); register_name = "SRSConf3"; break; - case 5: + case CP0_REG06__SRSCONF4: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf4)); register_name = "SRSConf4"; break; - case 6: + case CP0_REG06__PWCTL: check_pw(ctx); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWCtl)); register_name = "PWCtl"; @@ -7085,7 +7086,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_07: switch (sel) { - case 0: + case CP0_REG07__HWRENA: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_HWREna)); register_name = "HWREna"; @@ -7096,22 +7097,22 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_08: switch (sel) { - case 0: + case CP0_REG08__BADVADDR: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); tcg_gen_ext32s_tl(arg, arg); register_name = "BadVAddr"; break; - case 1: + case CP0_REG08__BADINSTR: CP0_CHECK(ctx->bi); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr)); register_name = "BadInstr"; break; - case 2: + case CP0_REG08__BADINSTRP: CP0_CHECK(ctx->bp); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP)); register_name = "BadInstrP"; break; - case 3: + case CP0_REG08__BADINSTRX: CP0_CHECK(ctx->bi); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrX)); tcg_gen_andi_tl(arg, arg, ~0xffff); @@ -7123,7 +7124,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_09: switch (sel) { - case 0: + case CP0_REG09__COUNT: /* Mark as an IO operation because we read the time. */ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); @@ -7138,12 +7139,12 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) ctx->base.is_jmp = DISAS_EXIT; register_name = "Count"; break; - case 6: + case CP0_REG09__SAARI: CP0_CHECK(ctx->saar); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SAARI)); register_name = "SAARI"; break; - case 7: + case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); gen_helper_mfc0_saar(arg, cpu_env); register_name = "SAAR"; @@ -7154,7 +7155,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_10: switch (sel) { - case 0: + case CP0_REG10__ENTRYHI: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryHi)); tcg_gen_ext32s_tl(arg, arg); register_name = "EntryHi"; @@ -7165,7 +7166,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_11: switch (sel) { - case 0: + case CP0_REG11__COMPARE: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Compare)); register_name = "Compare"; break; @@ -7176,21 +7177,21 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_12: switch (sel) { - case 0: + case CP0_REG12__STATUS: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Status)); register_name = "Status"; break; - case 1: + case CP0_REG12__INTCTL: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_IntCtl)); register_name = "IntCtl"; break; - case 2: + case CP0_REG12__SRSCTL: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSCtl)); register_name = "SRSCtl"; break; - case 3: + case CP0_REG12__SRSMAP: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSMap)); register_name = "SRSMap"; @@ -7201,7 +7202,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_13: switch (sel) { - case 0: + case CP0_REG13__CAUSE: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Cause)); register_name = "Cause"; break; @@ -7211,7 +7212,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_14: switch (sel) { - case 0: + case CP0_REG14__EPC: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC)); tcg_gen_ext32s_tl(arg, arg); register_name = "EPC"; @@ -7222,17 +7223,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_15: switch (sel) { - case 0: + case CP0_REG15__PRID: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PRid)); register_name = "PRid"; break; - case 1: + case CP0_REG15__EBASE: check_insn(ctx, ISA_MIPS32R2); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EBase)); tcg_gen_ext32s_tl(arg, arg); register_name = "EBase"; break; - case 3: + case CP0_REG15__CMGCRBASE: check_insn(ctx, ISA_MIPS32R2); CP0_CHECK(ctx->cmgcr); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_CMGCRBase)); @@ -7245,36 +7246,36 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_16: switch (sel) { - case 0: + case CP0_REG16__CONFIG: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config0)); register_name = "Config"; break; - case 1: + case CP0_REG16__CONFIG1: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config1)); register_name = "Config1"; break; - case 2: + case CP0_REG16__CONFIG2: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config2)); register_name = "Config2"; break; - case 3: + case CP0_REG16__CONFIG3: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config3)); register_name = "Config3"; break; - case 4: + case CP0_REG16__CONFIG4: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config4)); register_name = "Config4"; break; - case 5: + case CP0_REG16__CONFIG5: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config5)); register_name = "Config5"; break; /* 6,7 are implementation dependent */ - case 6: + case CP0_REG16__CONFIG6: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6)); register_name = "Config6"; break; - case 7: + case CP0_REG16__CONFIG7: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config7)); register_name = "Config7"; break; @@ -7284,16 +7285,16 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_17: switch (sel) { - case 0: + case CP0_REG17__LLADDR: gen_helper_mfc0_lladdr(arg, cpu_env); register_name = "LLAddr"; break; - case 1: + case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); gen_helper_mfc0_maar(arg, cpu_env); register_name = "MAAR"; break; - case 2: + case CP0_REG17__MAARI: CP0_CHECK(ctx->mrp); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_MAARI)); register_name = "MAARI"; @@ -7304,14 +7305,14 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_18: switch (sel) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG18__WATCHLO0: + case CP0_REG18__WATCHLO1: + case CP0_REG18__WATCHLO2: + case CP0_REG18__WATCHLO3: + case CP0_REG18__WATCHLO4: + case CP0_REG18__WATCHLO5: + case CP0_REG18__WATCHLO6: + case CP0_REG18__WATCHLO7: CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR)); gen_helper_1e0i(mfc0_watchlo, arg, sel); register_name = "WatchLo"; @@ -7322,14 +7323,14 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_19: switch (sel) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG19__WATCHHI0: + case CP0_REG19__WATCHHI1: + case CP0_REG19__WATCHHI2: + case CP0_REG19__WATCHHI3: + case CP0_REG19__WATCHHI4: + case CP0_REG19__WATCHHI5: + case CP0_REG19__WATCHHI6: + case CP0_REG19__WATCHHI7: CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR)); gen_helper_1e0i(mfc0_watchhi, arg, sel); register_name = "WatchHi"; @@ -7340,7 +7341,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_20: switch (sel) { - case 0: + case CP0_REG20__XCONTEXT: #if defined(TARGET_MIPS64) check_insn(ctx, ISA_MIPS3); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext)); @@ -7370,25 +7371,34 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_23: switch (sel) { - case 0: + case CP0_REG23__DEBUG: gen_helper_mfc0_debug(arg, cpu_env); /* EJTAG support */ register_name = "Debug"; break; - case 1: -// gen_helper_mfc0_tracecontrol(arg); /* PDtrace support */ + case CP0_REG23__TRACECONTROL: + /* PDtrace support */ + /* gen_helper_mfc0_tracecontrol(arg); */ register_name = "TraceControl"; goto cp0_unimplemented; - case 2: -// gen_helper_mfc0_tracecontrol2(arg); /* PDtrace support */ + case CP0_REG23__TRACECONTROL2: + /* PDtrace support */ + /* gen_helper_mfc0_tracecontrol2(arg); */ register_name = "TraceControl2"; goto cp0_unimplemented; - case 3: -// gen_helper_mfc0_usertracedata(arg); /* PDtrace support */ - register_name = "UserTraceData"; + case CP0_REG23__USERTRACEDATA1: + /* PDtrace support */ + /* gen_helper_mfc0_usertracedata1(arg);*/ + register_name = "UserTraceData1"; goto cp0_unimplemented; - case 4: -// gen_helper_mfc0_tracebpc(arg); /* PDtrace support */ - register_name = "TraceBPC"; + case CP0_REG23__TRACEIBPC: + /* PDtrace support */ + /* gen_helper_mfc0_traceibpc(arg); */ + register_name = "TraceIBPC"; + goto cp0_unimplemented; + case CP0_REG23__TRACEDBPC: + /* PDtrace support */ + /* gen_helper_mfc0_tracedbpc(arg); */ + register_name = "TraceDBPC"; goto cp0_unimplemented; default: goto cp0_unimplemented; @@ -7396,7 +7406,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_24: switch (sel) { - case 0: + case CP0_REG24__DEPC: /* EJTAG support */ tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC)); tcg_gen_ext32s_tl(arg, arg); @@ -7408,35 +7418,35 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_25: switch (sel) { - case 0: + case CP0_REG25__PERFCTL0: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Performance0)); register_name = "Performance0"; break; - case 1: + case CP0_REG25__PERFCNT0: /* gen_helper_mfc0_performance1(arg); */ register_name = "Performance1"; goto cp0_unimplemented; - case 2: + case CP0_REG25__PERFCTL1: /* gen_helper_mfc0_performance2(arg); */ register_name = "Performance2"; goto cp0_unimplemented; - case 3: + case CP0_REG25__PERFCNT1: /* gen_helper_mfc0_performance3(arg); */ register_name = "Performance3"; goto cp0_unimplemented; - case 4: + case CP0_REG25__PERFCTL2: /* gen_helper_mfc0_performance4(arg); */ register_name = "Performance4"; goto cp0_unimplemented; - case 5: + case CP0_REG25__PERFCNT2: /* gen_helper_mfc0_performance5(arg); */ register_name = "Performance5"; goto cp0_unimplemented; - case 6: + case CP0_REG25__PERFCTL3: /* gen_helper_mfc0_performance6(arg); */ register_name = "Performance6"; goto cp0_unimplemented; - case 7: + case CP0_REG25__PERFCNT3: /* gen_helper_mfc0_performance7(arg); */ register_name = "Performance7"; goto cp0_unimplemented; @@ -7446,7 +7456,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_26: switch (sel) { - case 0: + case CP0_REG26__ERRCTL: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_ErrCtl)); register_name = "ErrCtl"; break; @@ -7456,10 +7466,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_27: switch (sel) { - case 0: - case 1: - case 2: - case 3: + case CP0_REG27__CACHERR: tcg_gen_movi_tl(arg, 0); /* unimplemented */ register_name = "CacheErr"; break; @@ -7469,10 +7476,10 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_28: switch (sel) { - case 0: - case 2: - case 4: - case 6: + case CP0_REG28__TAGLO: + case CP0_REG28__TAGLO1: + case CP0_REG28__TAGLO2: + case CP0_REG28__TAGLO3: { TCGv_i64 tmp = tcg_temp_new_i64(); tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUMIPSState, CP0_TagLo)); @@ -7481,10 +7488,10 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) } register_name = "TagLo"; break; - case 1: - case 3: - case 5: - case 7: + case CP0_REG28__DATALO: + case CP0_REG28__DATALO1: + case CP0_REG28__DATALO2: + case CP0_REG28__DATALO3: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataLo)); register_name = "DataLo"; break; @@ -7494,17 +7501,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_29: switch (sel) { - case 0: - case 2: - case 4: - case 6: + case CP0_REG29__TAGHI: + case CP0_REG29__TAGHI1: + case CP0_REG29__TAGHI2: + case CP0_REG29__TAGHI3: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagHi)); register_name = "TagHi"; break; - case 1: - case 3: - case 5: - case 7: + case CP0_REG29__DATAHI: + case CP0_REG29__DATAHI1: + case CP0_REG29__DATAHI2: + case CP0_REG29__DATAHI3: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataHi)); register_name = "DataHi"; break; @@ -7514,7 +7521,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_30: switch (sel) { - case 0: + case CP0_REG30__ERROREPC: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); tcg_gen_ext32s_tl(arg, arg); register_name = "ErrorEPC"; @@ -7525,17 +7532,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_31: switch (sel) { - case 0: + case CP0_REG31__DESAVE: /* EJTAG support */ gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DESAVE)); register_name = "DESAVE"; break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG31__KSCRATCH1: + case CP0_REG31__KSCRATCH2: + case CP0_REG31__KSCRATCH3: + case CP0_REG31__KSCRATCH4: + case CP0_REG31__KSCRATCH5: + case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_KScratch[sel-2])); @@ -7573,26 +7580,26 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (reg) { case CP0_REGISTER_00: switch (sel) { - case 0: + case CP0_REG00__INDEX: gen_helper_mtc0_index(cpu_env, arg); register_name = "Index"; break; - case 1: + case CP0_REG00__MVPCONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_mvpcontrol(cpu_env, arg); register_name = "MVPControl"; break; - case 2: + case CP0_REG00__MVPCONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); /* ignored */ register_name = "MVPConf0"; break; - case 3: + case CP0_REG00__MVPCONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); /* ignored */ register_name = "MVPConf1"; break; - case 4: + case CP0_REG00__VPCONTROL: CP0_CHECK(ctx->vp); /* ignored */ register_name = "VPControl"; @@ -7603,43 +7610,43 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_01: switch (sel) { - case 0: + case CP0_REG01__RANDOM: /* ignored */ register_name = "Random"; break; - case 1: + case CP0_REG01__VPECONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpecontrol(cpu_env, arg); register_name = "VPEControl"; break; - case 2: + case CP0_REG01__VPECONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeconf0(cpu_env, arg); register_name = "VPEConf0"; break; - case 3: + case CP0_REG01__VPECONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeconf1(cpu_env, arg); register_name = "VPEConf1"; break; - case 4: + case CP0_REG01__YQMASK: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_yqmask(cpu_env, arg); register_name = "YQMask"; break; - case 5: + case CP0_REG01__VPESCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule)); register_name = "VPESchedule"; break; - case 6: + case CP0_REG01__VPESCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); register_name = "VPEScheFBack"; break; - case 7: + case CP0_REG01__VPEOPT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeopt(cpu_env, arg); register_name = "VPEOpt"; @@ -7650,41 +7657,41 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_02: switch (sel) { - case 0: + case CP0_REG02__ENTRYLO0: gen_helper_mtc0_entrylo0(cpu_env, arg); register_name = "EntryLo0"; break; - case 1: + case CP0_REG02__TCSTATUS: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcstatus(cpu_env, arg); register_name = "TCStatus"; break; - case 2: + case CP0_REG02__TCBIND: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcbind(cpu_env, arg); register_name = "TCBind"; break; - case 3: + case CP0_REG02__TCRESTART: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcrestart(cpu_env, arg); register_name = "TCRestart"; break; - case 4: + case CP0_REG02__TCHALT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tchalt(cpu_env, arg); register_name = "TCHalt"; break; - case 5: + case CP0_REG02__TCCONTEXT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tccontext(cpu_env, arg); register_name = "TCContext"; break; - case 6: + case CP0_REG02__TCSCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcschedule(cpu_env, arg); register_name = "TCSchedule"; break; - case 7: + case CP0_REG02__TCSCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcschefback(cpu_env, arg); register_name = "TCScheFBack"; @@ -7695,11 +7702,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_03: switch (sel) { - case 0: + case CP0_REG03__ENTRYLO1: gen_helper_mtc0_entrylo1(cpu_env, arg); register_name = "EntryLo1"; break; - case 1: + case CP0_REG03__GLOBALNUM: CP0_CHECK(ctx->vp); /* ignored */ register_name = "GlobalNumber"; @@ -7710,15 +7717,16 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_04: switch (sel) { - case 0: + case CP0_REG04__CONTEXT: gen_helper_mtc0_context(cpu_env, arg); register_name = "Context"; break; - case 1: -// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */ + case CP0_REG04__CONTEXTCONFIG: + /* SmartMIPS ASE */ + /* gen_helper_mtc0_contextconfig(arg); */ register_name = "ContextConfig"; goto cp0_unimplemented; - case 2: + case CP0_REG04__USERLOCAL: CP0_CHECK(ctx->ulri); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); @@ -7730,42 +7738,42 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_05: switch (sel) { - case 0: + case CP0_REG05__PAGEMASK: gen_helper_mtc0_pagemask(cpu_env, arg); register_name = "PageMask"; break; - case 1: + case CP0_REG05__PAGEGRAIN: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_pagegrain(cpu_env, arg); register_name = "PageGrain"; ctx->base.is_jmp = DISAS_STOP; break; - case 2: + case CP0_REG05__SEGCTL0: CP0_CHECK(ctx->sc); gen_helper_mtc0_segctl0(cpu_env, arg); register_name = "SegCtl0"; break; - case 3: + case CP0_REG05__SEGCTL1: CP0_CHECK(ctx->sc); gen_helper_mtc0_segctl1(cpu_env, arg); register_name = "SegCtl1"; break; - case 4: + case CP0_REG05__SEGCTL2: CP0_CHECK(ctx->sc); gen_helper_mtc0_segctl2(cpu_env, arg); register_name = "SegCtl2"; break; - case 5: + case CP0_REG05__PWBASE: check_pw(ctx); gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_PWBase)); register_name = "PWBase"; break; - case 6: + case CP0_REG05__PWFIELD: check_pw(ctx); gen_helper_mtc0_pwfield(cpu_env, arg); register_name = "PWField"; break; - case 7: + case CP0_REG05__PWSIZE: check_pw(ctx); gen_helper_mtc0_pwsize(cpu_env, arg); register_name = "PWSize"; @@ -7776,36 +7784,36 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_06: switch (sel) { - case 0: + case CP0_REG06__WIRED: gen_helper_mtc0_wired(cpu_env, arg); register_name = "Wired"; break; - case 1: + case CP0_REG06__SRSCONF0: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf0(cpu_env, arg); register_name = "SRSConf0"; break; - case 2: + case CP0_REG06__SRSCONF1: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf1(cpu_env, arg); register_name = "SRSConf1"; break; - case 3: + case CP0_REG06__SRSCONF2: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf2(cpu_env, arg); register_name = "SRSConf2"; break; - case 4: + case CP0_REG06__SRSCONF3: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf3(cpu_env, arg); register_name = "SRSConf3"; break; - case 5: + case CP0_REG06__SRSCONF4: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf4(cpu_env, arg); register_name = "SRSConf4"; break; - case 6: + case CP0_REG06__PWCTL: check_pw(ctx); gen_helper_mtc0_pwctl(cpu_env, arg); register_name = "PWCtl"; @@ -7816,7 +7824,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_07: switch (sel) { - case 0: + case CP0_REG07__HWRENA: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_hwrena(cpu_env, arg); ctx->base.is_jmp = DISAS_STOP; @@ -7828,19 +7836,19 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_08: switch (sel) { - case 0: + case CP0_REG08__BADVADDR: /* ignored */ register_name = "BadVAddr"; break; - case 1: + case CP0_REG08__BADINSTR: /* ignored */ register_name = "BadInstr"; break; - case 2: + case CP0_REG08__BADINSTRP: /* ignored */ register_name = "BadInstrP"; break; - case 3: + case CP0_REG08__BADINSTRX: /* ignored */ register_name = "BadInstrX"; break; @@ -7850,16 +7858,16 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_09: switch (sel) { - case 0: + case CP0_REG09__COUNT: gen_helper_mtc0_count(cpu_env, arg); register_name = "Count"; break; - case 6: + case CP0_REG09__SAARI: CP0_CHECK(ctx->saar); gen_helper_mtc0_saari(cpu_env, arg); register_name = "SAARI"; break; - case 7: + case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); gen_helper_mtc0_saar(cpu_env, arg); register_name = "SAAR"; @@ -7870,7 +7878,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_10: switch (sel) { - case 0: + case CP0_REG10__ENTRYHI: gen_helper_mtc0_entryhi(cpu_env, arg); register_name = "EntryHi"; break; @@ -7880,7 +7888,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_11: switch (sel) { - case 0: + case CP0_REG11__COMPARE: gen_helper_mtc0_compare(cpu_env, arg); register_name = "Compare"; break; @@ -7891,7 +7899,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_12: switch (sel) { - case 0: + case CP0_REG12__STATUS: save_cpu_state(ctx, 1); gen_helper_mtc0_status(cpu_env, arg); /* DISAS_STOP isn't good enough here, hflags may have changed. */ @@ -7899,21 +7907,21 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) ctx->base.is_jmp = DISAS_EXIT; register_name = "Status"; break; - case 1: + case CP0_REG12__INTCTL: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_intctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "IntCtl"; break; - case 2: + case CP0_REG12__SRSCTL: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "SRSCtl"; break; - case 3: + case CP0_REG12__SRSMAP: check_insn(ctx, ISA_MIPS32R2); gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap)); /* Stop translation as we may have switched the execution mode */ @@ -7926,7 +7934,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_13: switch (sel) { - case 0: + case CP0_REG13__CAUSE: save_cpu_state(ctx, 1); gen_helper_mtc0_cause(cpu_env, arg); /* @@ -7944,7 +7952,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_14: switch (sel) { - case 0: + case CP0_REG14__EPC: tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC)); register_name = "EPC"; break; @@ -7954,11 +7962,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_15: switch (sel) { - case 0: + case CP0_REG15__PRID: /* ignored */ register_name = "PRid"; break; - case 1: + case CP0_REG15__EBASE: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_ebase(cpu_env, arg); register_name = "EBase"; @@ -7969,45 +7977,45 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_16: switch (sel) { - case 0: + case CP0_REG16__CONFIG: gen_helper_mtc0_config0(cpu_env, arg); register_name = "Config"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; break; - case 1: + case CP0_REG16__CONFIG1: /* ignored, read only */ register_name = "Config1"; break; - case 2: + case CP0_REG16__CONFIG2: gen_helper_mtc0_config2(cpu_env, arg); register_name = "Config2"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; break; - case 3: + case CP0_REG16__CONFIG3: gen_helper_mtc0_config3(cpu_env, arg); register_name = "Config3"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; break; - case 4: + case CP0_REG16__CONFIG4: gen_helper_mtc0_config4(cpu_env, arg); register_name = "Config4"; ctx->base.is_jmp = DISAS_STOP; break; - case 5: + case CP0_REG16__CONFIG5: gen_helper_mtc0_config5(cpu_env, arg); register_name = "Config5"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; break; /* 6,7 are implementation dependent */ - case 6: + case CP0_REG16__CONFIG6: /* ignored */ register_name = "Config6"; break; - case 7: + case CP0_REG16__CONFIG7: /* ignored */ register_name = "Config7"; break; @@ -8018,16 +8026,16 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_17: switch (sel) { - case 0: + case CP0_REG17__LLADDR: gen_helper_mtc0_lladdr(cpu_env, arg); register_name = "LLAddr"; break; - case 1: + case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); gen_helper_mtc0_maar(cpu_env, arg); register_name = "MAAR"; break; - case 2: + case CP0_REG17__MAARI: CP0_CHECK(ctx->mrp); gen_helper_mtc0_maari(cpu_env, arg); register_name = "MAARI"; @@ -8038,14 +8046,14 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_18: switch (sel) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG18__WATCHLO0: + case CP0_REG18__WATCHLO1: + case CP0_REG18__WATCHLO2: + case CP0_REG18__WATCHLO3: + case CP0_REG18__WATCHLO4: + case CP0_REG18__WATCHLO5: + case CP0_REG18__WATCHLO6: + case CP0_REG18__WATCHLO7: CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR)); gen_helper_0e1i(mtc0_watchlo, arg, sel); register_name = "WatchLo"; @@ -8056,14 +8064,14 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_19: switch (sel) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG19__WATCHHI0: + case CP0_REG19__WATCHHI1: + case CP0_REG19__WATCHHI2: + case CP0_REG19__WATCHHI3: + case CP0_REG19__WATCHHI4: + case CP0_REG19__WATCHHI5: + case CP0_REG19__WATCHHI6: + case CP0_REG19__WATCHHI7: CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR)); gen_helper_0e1i(mtc0_watchhi, arg, sel); register_name = "WatchHi"; @@ -8074,7 +8082,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_20: switch (sel) { - case 0: + case CP0_REG20__XCONTEXT: #if defined(TARGET_MIPS64) check_insn(ctx, ISA_MIPS3); gen_helper_mtc0_xcontext(cpu_env, arg); @@ -8103,38 +8111,49 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_23: switch (sel) { - case 0: + case CP0_REG23__DEBUG: gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */ /* DISAS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->base.pc_next + 4); ctx->base.is_jmp = DISAS_EXIT; register_name = "Debug"; break; - case 1: -// gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */ + case CP0_REG23__TRACECONTROL: + /* PDtrace support */ + /* gen_helper_mtc0_tracecontrol(cpu_env, arg); */ register_name = "TraceControl"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; goto cp0_unimplemented; - case 2: -// gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */ + case CP0_REG23__TRACECONTROL2: + /* PDtrace support */ + /* gen_helper_mtc0_tracecontrol2(cpu_env, arg); */ register_name = "TraceControl2"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; goto cp0_unimplemented; - case 3: + case CP0_REG23__USERTRACEDATA1: /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; -// gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */ + /* PDtrace support */ + /* gen_helper_mtc0_usertracedata1(cpu_env, arg);*/ register_name = "UserTraceData"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; goto cp0_unimplemented; - case 4: -// gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */ + case CP0_REG23__TRACEIBPC: + /* PDtrace support */ + /* gen_helper_mtc0_traceibpc(cpu_env, arg); */ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; - register_name = "TraceBPC"; + register_name = "TraceIBPC"; + goto cp0_unimplemented; + case CP0_REG23__TRACEDBPC: + /* PDtrace support */ + /* gen_helper_mtc0_tracedbpc(cpu_env, arg); */ + /* Stop translation as we may have switched the execution mode */ + ctx->base.is_jmp = DISAS_STOP; + register_name = "TraceDBPC"; goto cp0_unimplemented; default: goto cp0_unimplemented; @@ -8142,7 +8161,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_24: switch (sel) { - case 0: + case CP0_REG24__DEPC: /* EJTAG support */ tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC)); register_name = "DEPC"; @@ -8153,35 +8172,35 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_25: switch (sel) { - case 0: + case CP0_REG25__PERFCTL0: gen_helper_mtc0_performance0(cpu_env, arg); register_name = "Performance0"; break; - case 1: + case CP0_REG25__PERFCNT0: /* gen_helper_mtc0_performance1(arg); */ register_name = "Performance1"; goto cp0_unimplemented; - case 2: + case CP0_REG25__PERFCTL1: /* gen_helper_mtc0_performance2(arg); */ register_name = "Performance2"; goto cp0_unimplemented; - case 3: + case CP0_REG25__PERFCNT1: /* gen_helper_mtc0_performance3(arg); */ register_name = "Performance3"; goto cp0_unimplemented; - case 4: + case CP0_REG25__PERFCTL2: /* gen_helper_mtc0_performance4(arg); */ register_name = "Performance4"; goto cp0_unimplemented; - case 5: + case CP0_REG25__PERFCNT2: /* gen_helper_mtc0_performance5(arg); */ register_name = "Performance5"; goto cp0_unimplemented; - case 6: + case CP0_REG25__PERFCTL3: /* gen_helper_mtc0_performance6(arg); */ register_name = "Performance6"; goto cp0_unimplemented; - case 7: + case CP0_REG25__PERFCNT3: /* gen_helper_mtc0_performance7(arg); */ register_name = "Performance7"; goto cp0_unimplemented; @@ -8191,7 +8210,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_26: switch (sel) { - case 0: + case CP0_REG26__ERRCTL: gen_helper_mtc0_errctl(cpu_env, arg); ctx->base.is_jmp = DISAS_STOP; register_name = "ErrCtl"; @@ -8202,10 +8221,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_27: switch (sel) { - case 0: - case 1: - case 2: - case 3: + case CP0_REG27__CACHERR: /* ignored */ register_name = "CacheErr"; break; @@ -8215,17 +8231,17 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_28: switch (sel) { - case 0: - case 2: - case 4: - case 6: + case CP0_REG28__TAGLO: + case CP0_REG28__TAGLO1: + case CP0_REG28__TAGLO2: + case CP0_REG28__TAGLO3: gen_helper_mtc0_taglo(cpu_env, arg); register_name = "TagLo"; break; - case 1: - case 3: - case 5: - case 7: + case CP0_REG28__DATALO: + case CP0_REG28__DATALO1: + case CP0_REG28__DATALO2: + case CP0_REG28__DATALO3: gen_helper_mtc0_datalo(cpu_env, arg); register_name = "DataLo"; break; @@ -8235,17 +8251,17 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_29: switch (sel) { - case 0: - case 2: - case 4: - case 6: + case CP0_REG29__TAGHI: + case CP0_REG29__TAGHI1: + case CP0_REG29__TAGHI2: + case CP0_REG29__TAGHI3: gen_helper_mtc0_taghi(cpu_env, arg); register_name = "TagHi"; break; - case 1: - case 3: - case 5: - case 7: + case CP0_REG29__DATAHI: + case CP0_REG29__DATAHI1: + case CP0_REG29__DATAHI2: + case CP0_REG29__DATAHI3: gen_helper_mtc0_datahi(cpu_env, arg); register_name = "DataHi"; break; @@ -8256,7 +8272,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_30: switch (sel) { - case 0: + case CP0_REG30__ERROREPC: tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); register_name = "ErrorEPC"; break; @@ -8266,17 +8282,17 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_31: switch (sel) { - case 0: + case CP0_REG31__DESAVE: /* EJTAG support */ gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_DESAVE)); register_name = "DESAVE"; break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG31__KSCRATCH1: + case CP0_REG31__KSCRATCH2: + case CP0_REG31__KSCRATCH3: + case CP0_REG31__KSCRATCH4: + case CP0_REG31__KSCRATCH5: + case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_KScratch[sel-2])); @@ -8319,26 +8335,26 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (reg) { case CP0_REGISTER_00: switch (sel) { - case 0: + case CP0_REG00__INDEX: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Index)); register_name = "Index"; break; - case 1: + case CP0_REG00__MVPCONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpcontrol(arg, cpu_env); register_name = "MVPControl"; break; - case 2: + case CP0_REG00__MVPCONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpconf0(arg, cpu_env); register_name = "MVPConf0"; break; - case 3: + case CP0_REG00__MVPCONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpconf1(arg, cpu_env); register_name = "MVPConf1"; break; - case 4: + case CP0_REG00__VPCONTROL: CP0_CHECK(ctx->vp); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPControl)); register_name = "VPControl"; @@ -8349,42 +8365,42 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_01: switch (sel) { - case 0: + case CP0_REG01__RANDOM: CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6)); gen_helper_mfc0_random(arg, cpu_env); register_name = "Random"; break; - case 1: + case CP0_REG01__VPECONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl)); register_name = "VPEControl"; break; - case 2: + case CP0_REG01__VPECONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0)); register_name = "VPEConf0"; break; - case 3: + case CP0_REG01__VPECONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1)); register_name = "VPEConf1"; break; - case 4: + case CP0_REG01__YQMASK: CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_YQMask)); register_name = "YQMask"; break; - case 5: + case CP0_REG01__VPESCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule)); register_name = "VPESchedule"; break; - case 6: + case CP0_REG01__VPESCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); register_name = "VPEScheFBack"; break; - case 7: + case CP0_REG01__VPEOPT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt)); register_name = "VPEOpt"; @@ -8395,41 +8411,41 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_02: switch (sel) { - case 0: + case CP0_REG02__ENTRYLO0: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo0)); register_name = "EntryLo0"; break; - case 1: + case CP0_REG02__TCSTATUS: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcstatus(arg, cpu_env); register_name = "TCStatus"; break; - case 2: + case CP0_REG02__TCBIND: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcbind(arg, cpu_env); register_name = "TCBind"; break; - case 3: + case CP0_REG02__TCRESTART: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_dmfc0_tcrestart(arg, cpu_env); register_name = "TCRestart"; break; - case 4: + case CP0_REG02__TCHALT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_dmfc0_tchalt(arg, cpu_env); register_name = "TCHalt"; break; - case 5: + case CP0_REG02__TCCONTEXT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_dmfc0_tccontext(arg, cpu_env); register_name = "TCContext"; break; - case 6: + case CP0_REG02__TCSCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_dmfc0_tcschedule(arg, cpu_env); register_name = "TCSchedule"; break; - case 7: + case CP0_REG02__TCSCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_dmfc0_tcschefback(arg, cpu_env); register_name = "TCScheFBack"; @@ -8440,11 +8456,11 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_03: switch (sel) { - case 0: + case CP0_REG03__ENTRYLO1: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo1)); register_name = "EntryLo1"; break; - case 1: + case CP0_REG03__GLOBALNUM: CP0_CHECK(ctx->vp); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_GlobalNumber)); register_name = "GlobalNumber"; @@ -8455,15 +8471,16 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_04: switch (sel) { - case 0: + case CP0_REG04__CONTEXT: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_Context)); register_name = "Context"; break; - case 1: -// gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */ + case CP0_REG04__CONTEXTCONFIG: + /* SmartMIPS ASE */ + /* gen_helper_dmfc0_contextconfig(arg); */ register_name = "ContextConfig"; goto cp0_unimplemented; - case 2: + case CP0_REG04__USERLOCAL: CP0_CHECK(ctx->ulri); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); @@ -8475,41 +8492,41 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_05: switch (sel) { - case 0: + case CP0_REG05__PAGEMASK: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageMask)); register_name = "PageMask"; break; - case 1: + case CP0_REG05__PAGEGRAIN: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain)); register_name = "PageGrain"; break; - case 2: + case CP0_REG05__SEGCTL0: CP0_CHECK(ctx->sc); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0)); register_name = "SegCtl0"; break; - case 3: + case CP0_REG05__SEGCTL1: CP0_CHECK(ctx->sc); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1)); register_name = "SegCtl1"; break; - case 4: + case CP0_REG05__SEGCTL2: CP0_CHECK(ctx->sc); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2)); register_name = "SegCtl2"; break; - case 5: + case CP0_REG05__PWBASE: check_pw(ctx); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWBase)); register_name = "PWBase"; break; - case 6: + case CP0_REG05__PWFIELD: check_pw(ctx); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWField)); register_name = "PWField"; break; - case 7: + case CP0_REG05__PWSIZE: check_pw(ctx); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWSize)); register_name = "PWSize"; @@ -8520,36 +8537,36 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_06: switch (sel) { - case 0: + case CP0_REG06__WIRED: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Wired)); register_name = "Wired"; break; - case 1: + case CP0_REG06__SRSCONF0: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf0)); register_name = "SRSConf0"; break; - case 2: + case CP0_REG06__SRSCONF1: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf1)); register_name = "SRSConf1"; break; - case 3: + case CP0_REG06__SRSCONF2: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf2)); register_name = "SRSConf2"; break; - case 4: + case CP0_REG06__SRSCONF3: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf3)); register_name = "SRSConf3"; break; - case 5: + case CP0_REG06__SRSCONF4: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf4)); register_name = "SRSConf4"; break; - case 6: + case CP0_REG06__PWCTL: check_pw(ctx); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWCtl)); register_name = "PWCtl"; @@ -8560,7 +8577,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_07: switch (sel) { - case 0: + case CP0_REG07__HWRENA: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_HWREna)); register_name = "HWREna"; @@ -8571,21 +8588,21 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_08: switch (sel) { - case 0: + case CP0_REG08__BADVADDR: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); register_name = "BadVAddr"; break; - case 1: + case CP0_REG08__BADINSTR: CP0_CHECK(ctx->bi); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr)); register_name = "BadInstr"; break; - case 2: + case CP0_REG08__BADINSTRP: CP0_CHECK(ctx->bp); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP)); register_name = "BadInstrP"; break; - case 3: + case CP0_REG08__BADINSTRX: CP0_CHECK(ctx->bi); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrX)); tcg_gen_andi_tl(arg, arg, ~0xffff); @@ -8597,7 +8614,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_09: switch (sel) { - case 0: + case CP0_REG09__COUNT: /* Mark as an IO operation because we read the time. */ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); @@ -8612,12 +8629,12 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) ctx->base.is_jmp = DISAS_EXIT; register_name = "Count"; break; - case 6: + case CP0_REG09__SAARI: CP0_CHECK(ctx->saar); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SAARI)); register_name = "SAARI"; break; - case 7: + case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); gen_helper_dmfc0_saar(arg, cpu_env); register_name = "SAAR"; @@ -8628,7 +8645,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_10: switch (sel) { - case 0: + case CP0_REG10__ENTRYHI: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryHi)); register_name = "EntryHi"; break; @@ -8638,7 +8655,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_11: switch (sel) { - case 0: + case CP0_REG11__COMPARE: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Compare)); register_name = "Compare"; break; @@ -8649,21 +8666,21 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_12: switch (sel) { - case 0: + case CP0_REG12__STATUS: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Status)); register_name = "Status"; break; - case 1: + case CP0_REG12__INTCTL: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_IntCtl)); register_name = "IntCtl"; break; - case 2: + case CP0_REG12__SRSCTL: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSCtl)); register_name = "SRSCtl"; break; - case 3: + case CP0_REG12__SRSMAP: check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSMap)); register_name = "SRSMap"; @@ -8674,7 +8691,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_13: switch (sel) { - case 0: + case CP0_REG13__CAUSE: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Cause)); register_name = "Cause"; break; @@ -8684,7 +8701,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_14: switch (sel) { - case 0: + case CP0_REG14__EPC: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC)); register_name = "EPC"; break; @@ -8694,16 +8711,16 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_15: switch (sel) { - case 0: + case CP0_REG15__PRID: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PRid)); register_name = "PRid"; break; - case 1: + case CP0_REG15__EBASE: check_insn(ctx, ISA_MIPS32R2); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EBase)); register_name = "EBase"; break; - case 3: + case CP0_REG15__CMGCRBASE: check_insn(ctx, ISA_MIPS32R2); CP0_CHECK(ctx->cmgcr); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_CMGCRBase)); @@ -8715,36 +8732,36 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_16: switch (sel) { - case 0: + case CP0_REG16__CONFIG: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config0)); register_name = "Config"; break; - case 1: + case CP0_REG16__CONFIG1: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config1)); register_name = "Config1"; break; - case 2: + case CP0_REG16__CONFIG2: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config2)); register_name = "Config2"; break; - case 3: + case CP0_REG16__CONFIG3: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config3)); register_name = "Config3"; break; - case 4: + case CP0_REG16__CONFIG4: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config4)); register_name = "Config4"; break; - case 5: + case CP0_REG16__CONFIG5: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config5)); register_name = "Config5"; break; /* 6,7 are implementation dependent */ - case 6: + case CP0_REG16__CONFIG6: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6)); register_name = "Config6"; break; - case 7: + case CP0_REG16__CONFIG7: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config7)); register_name = "Config7"; break; @@ -8754,16 +8771,16 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_17: switch (sel) { - case 0: + case CP0_REG17__LLADDR: gen_helper_dmfc0_lladdr(arg, cpu_env); register_name = "LLAddr"; break; - case 1: + case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); gen_helper_dmfc0_maar(arg, cpu_env); register_name = "MAAR"; break; - case 2: + case CP0_REG17__MAARI: CP0_CHECK(ctx->mrp); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_MAARI)); register_name = "MAARI"; @@ -8774,14 +8791,14 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_18: switch (sel) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG18__WATCHLO0: + case CP0_REG18__WATCHLO1: + case CP0_REG18__WATCHLO2: + case CP0_REG18__WATCHLO3: + case CP0_REG18__WATCHLO4: + case CP0_REG18__WATCHLO5: + case CP0_REG18__WATCHLO6: + case CP0_REG18__WATCHLO7: CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR)); gen_helper_1e0i(dmfc0_watchlo, arg, sel); register_name = "WatchLo"; @@ -8792,14 +8809,14 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_19: switch (sel) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG19__WATCHHI0: + case CP0_REG19__WATCHHI1: + case CP0_REG19__WATCHHI2: + case CP0_REG19__WATCHHI3: + case CP0_REG19__WATCHHI4: + case CP0_REG19__WATCHHI5: + case CP0_REG19__WATCHHI6: + case CP0_REG19__WATCHHI7: CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR)); gen_helper_1e0i(mfc0_watchhi, arg, sel); register_name = "WatchHi"; @@ -8810,7 +8827,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_20: switch (sel) { - case 0: + case CP0_REG20__XCONTEXT: check_insn(ctx, ISA_MIPS3); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext)); register_name = "XContext"; @@ -8837,25 +8854,34 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_23: switch (sel) { - case 0: + case CP0_REG23__DEBUG: gen_helper_mfc0_debug(arg, cpu_env); /* EJTAG support */ register_name = "Debug"; break; - case 1: -// gen_helper_dmfc0_tracecontrol(arg, cpu_env); /* PDtrace support */ + case CP0_REG23__TRACECONTROL: + /* PDtrace support */ + /* gen_helper_dmfc0_tracecontrol(arg, cpu_env); */ register_name = "TraceControl"; goto cp0_unimplemented; - case 2: -// gen_helper_dmfc0_tracecontrol2(arg, cpu_env); /* PDtrace support */ + case CP0_REG23__TRACECONTROL2: + /* PDtrace support */ + /* gen_helper_dmfc0_tracecontrol2(arg, cpu_env); */ register_name = "TraceControl2"; goto cp0_unimplemented; - case 3: -// gen_helper_dmfc0_usertracedata(arg, cpu_env); /* PDtrace support */ - register_name = "UserTraceData"; + case CP0_REG23__USERTRACEDATA1: + /* PDtrace support */ + /* gen_helper_dmfc0_usertracedata1(arg, cpu_env);*/ + register_name = "UserTraceData1"; goto cp0_unimplemented; - case 4: -// gen_helper_dmfc0_tracebpc(arg, cpu_env); /* PDtrace support */ - register_name = "TraceBPC"; + case CP0_REG23__TRACEIBPC: + /* PDtrace support */ + /* gen_helper_dmfc0_traceibpc(arg, cpu_env); */ + register_name = "TraceIBPC"; + goto cp0_unimplemented; + case CP0_REG23__TRACEDBPC: + /* PDtrace support */ + /* gen_helper_dmfc0_tracedbpc(arg, cpu_env); */ + register_name = "TraceDBPC"; goto cp0_unimplemented; default: goto cp0_unimplemented; @@ -8863,7 +8889,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_24: switch (sel) { - case 0: + case CP0_REG24__DEPC: /* EJTAG support */ tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC)); register_name = "DEPC"; @@ -8874,35 +8900,35 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_25: switch (sel) { - case 0: + case CP0_REG25__PERFCTL0: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Performance0)); register_name = "Performance0"; break; - case 1: + case CP0_REG25__PERFCNT0: /* gen_helper_dmfc0_performance1(arg); */ register_name = "Performance1"; goto cp0_unimplemented; - case 2: + case CP0_REG25__PERFCTL1: /* gen_helper_dmfc0_performance2(arg); */ register_name = "Performance2"; goto cp0_unimplemented; - case 3: + case CP0_REG25__PERFCNT1: /* gen_helper_dmfc0_performance3(arg); */ register_name = "Performance3"; goto cp0_unimplemented; - case 4: + case CP0_REG25__PERFCTL2: /* gen_helper_dmfc0_performance4(arg); */ register_name = "Performance4"; goto cp0_unimplemented; - case 5: + case CP0_REG25__PERFCNT2: /* gen_helper_dmfc0_performance5(arg); */ register_name = "Performance5"; goto cp0_unimplemented; - case 6: + case CP0_REG25__PERFCTL3: /* gen_helper_dmfc0_performance6(arg); */ register_name = "Performance6"; goto cp0_unimplemented; - case 7: + case CP0_REG25__PERFCNT3: /* gen_helper_dmfc0_performance7(arg); */ register_name = "Performance7"; goto cp0_unimplemented; @@ -8912,7 +8938,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_26: switch (sel) { - case 0: + case CP0_REG26__ERRCTL: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_ErrCtl)); register_name = "ErrCtl"; break; @@ -8923,10 +8949,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_27: switch (sel) { /* ignored */ - case 0: - case 1: - case 2: - case 3: + case CP0_REG27__CACHERR: tcg_gen_movi_tl(arg, 0); /* unimplemented */ register_name = "CacheErr"; break; @@ -8936,17 +8959,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_28: switch (sel) { - case 0: - case 2: - case 4: - case 6: + case CP0_REG28__TAGLO: + case CP0_REG28__TAGLO1: + case CP0_REG28__TAGLO2: + case CP0_REG28__TAGLO3: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagLo)); register_name = "TagLo"; break; - case 1: - case 3: - case 5: - case 7: + case CP0_REG28__DATALO: + case CP0_REG28__DATALO1: + case CP0_REG28__DATALO2: + case CP0_REG28__DATALO3: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataLo)); register_name = "DataLo"; break; @@ -8956,17 +8979,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_29: switch (sel) { - case 0: - case 2: - case 4: - case 6: + case CP0_REG29__TAGHI: + case CP0_REG29__TAGHI1: + case CP0_REG29__TAGHI2: + case CP0_REG29__TAGHI3: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagHi)); register_name = "TagHi"; break; - case 1: - case 3: - case 5: - case 7: + case CP0_REG29__DATAHI: + case CP0_REG29__DATAHI1: + case CP0_REG29__DATAHI2: + case CP0_REG29__DATAHI3: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataHi)); register_name = "DataHi"; break; @@ -8976,7 +8999,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_30: switch (sel) { - case 0: + case CP0_REG30__ERROREPC: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); register_name = "ErrorEPC"; break; @@ -8986,17 +9009,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_31: switch (sel) { - case 0: + case CP0_REG31__DESAVE: /* EJTAG support */ gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DESAVE)); register_name = "DESAVE"; break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG31__KSCRATCH1: + case CP0_REG31__KSCRATCH2: + case CP0_REG31__KSCRATCH3: + case CP0_REG31__KSCRATCH4: + case CP0_REG31__KSCRATCH5: + case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_KScratch[sel-2])); @@ -9033,26 +9056,26 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (reg) { case CP0_REGISTER_00: switch (sel) { - case 0: + case CP0_REG00__INDEX: gen_helper_mtc0_index(cpu_env, arg); register_name = "Index"; break; - case 1: + case CP0_REG00__MVPCONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_mvpcontrol(cpu_env, arg); register_name = "MVPControl"; break; - case 2: + case CP0_REG00__MVPCONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); /* ignored */ register_name = "MVPConf0"; break; - case 3: + case CP0_REG00__MVPCONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); /* ignored */ register_name = "MVPConf1"; break; - case 4: + case CP0_REG00__VPCONTROL: CP0_CHECK(ctx->vp); /* ignored */ register_name = "VPControl"; @@ -9063,41 +9086,41 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_01: switch (sel) { - case 0: + case CP0_REG01__RANDOM: /* ignored */ register_name = "Random"; break; - case 1: + case CP0_REG01__VPECONTROL: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpecontrol(cpu_env, arg); register_name = "VPEControl"; break; - case 2: + case CP0_REG01__VPECONF0: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeconf0(cpu_env, arg); register_name = "VPEConf0"; break; - case 3: + case CP0_REG01__VPECONF1: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeconf1(cpu_env, arg); register_name = "VPEConf1"; break; - case 4: + case CP0_REG01__YQMASK: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_yqmask(cpu_env, arg); register_name = "YQMask"; break; - case 5: + case CP0_REG01__VPESCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule)); register_name = "VPESchedule"; break; - case 6: + case CP0_REG01__VPESCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); register_name = "VPEScheFBack"; break; - case 7: + case CP0_REG01__VPEOPT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeopt(cpu_env, arg); register_name = "VPEOpt"; @@ -9108,41 +9131,41 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_02: switch (sel) { - case 0: + case CP0_REG02__ENTRYLO0: gen_helper_dmtc0_entrylo0(cpu_env, arg); register_name = "EntryLo0"; break; - case 1: + case CP0_REG02__TCSTATUS: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcstatus(cpu_env, arg); register_name = "TCStatus"; break; - case 2: + case CP0_REG02__TCBIND: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcbind(cpu_env, arg); register_name = "TCBind"; break; - case 3: + case CP0_REG02__TCRESTART: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcrestart(cpu_env, arg); register_name = "TCRestart"; break; - case 4: + case CP0_REG02__TCHALT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tchalt(cpu_env, arg); register_name = "TCHalt"; break; - case 5: + case CP0_REG02__TCCONTEXT: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tccontext(cpu_env, arg); register_name = "TCContext"; break; - case 6: + case CP0_REG02__TCSCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcschedule(cpu_env, arg); register_name = "TCSchedule"; break; - case 7: + case CP0_REG02__TCSCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcschefback(cpu_env, arg); register_name = "TCScheFBack"; @@ -9153,11 +9176,11 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_03: switch (sel) { - case 0: + case CP0_REG03__ENTRYLO1: gen_helper_dmtc0_entrylo1(cpu_env, arg); register_name = "EntryLo1"; break; - case 1: + case CP0_REG03__GLOBALNUM: CP0_CHECK(ctx->vp); /* ignored */ register_name = "GlobalNumber"; @@ -9168,15 +9191,16 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_04: switch (sel) { - case 0: + case CP0_REG04__CONTEXT: gen_helper_mtc0_context(cpu_env, arg); register_name = "Context"; break; - case 1: -// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */ + case CP0_REG04__CONTEXTCONFIG: + /* SmartMIPS ASE */ + /* gen_helper_dmtc0_contextconfig(arg); */ register_name = "ContextConfig"; goto cp0_unimplemented; - case 2: + case CP0_REG04__USERLOCAL: CP0_CHECK(ctx->ulri); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); @@ -9188,41 +9212,41 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_05: switch (sel) { - case 0: + case CP0_REG05__PAGEMASK: gen_helper_mtc0_pagemask(cpu_env, arg); register_name = "PageMask"; break; - case 1: + case CP0_REG05__PAGEGRAIN: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_pagegrain(cpu_env, arg); register_name = "PageGrain"; break; - case 2: + case CP0_REG05__SEGCTL0: CP0_CHECK(ctx->sc); gen_helper_mtc0_segctl0(cpu_env, arg); register_name = "SegCtl0"; break; - case 3: + case CP0_REG05__SEGCTL1: CP0_CHECK(ctx->sc); gen_helper_mtc0_segctl1(cpu_env, arg); register_name = "SegCtl1"; break; - case 4: + case CP0_REG05__SEGCTL2: CP0_CHECK(ctx->sc); gen_helper_mtc0_segctl2(cpu_env, arg); register_name = "SegCtl2"; break; - case 5: + case CP0_REG05__PWBASE: check_pw(ctx); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWBase)); register_name = "PWBase"; break; - case 6: + case CP0_REG05__PWFIELD: check_pw(ctx); gen_helper_mtc0_pwfield(cpu_env, arg); register_name = "PWField"; break; - case 7: + case CP0_REG05__PWSIZE: check_pw(ctx); gen_helper_mtc0_pwsize(cpu_env, arg); register_name = "PWSize"; @@ -9233,36 +9257,36 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_06: switch (sel) { - case 0: + case CP0_REG06__WIRED: gen_helper_mtc0_wired(cpu_env, arg); register_name = "Wired"; break; - case 1: + case CP0_REG06__SRSCONF0: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf0(cpu_env, arg); register_name = "SRSConf0"; break; - case 2: + case CP0_REG06__SRSCONF1: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf1(cpu_env, arg); register_name = "SRSConf1"; break; - case 3: + case CP0_REG06__SRSCONF2: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf2(cpu_env, arg); register_name = "SRSConf2"; break; - case 4: + case CP0_REG06__SRSCONF3: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf3(cpu_env, arg); register_name = "SRSConf3"; break; - case 5: + case CP0_REG06__SRSCONF4: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf4(cpu_env, arg); register_name = "SRSConf4"; break; - case 6: + case CP0_REG06__PWCTL: check_pw(ctx); gen_helper_mtc0_pwctl(cpu_env, arg); register_name = "PWCtl"; @@ -9273,7 +9297,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_07: switch (sel) { - case 0: + case CP0_REG07__HWRENA: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_hwrena(cpu_env, arg); ctx->base.is_jmp = DISAS_STOP; @@ -9285,19 +9309,19 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_08: switch (sel) { - case 0: + case CP0_REG08__BADVADDR: /* ignored */ register_name = "BadVAddr"; break; - case 1: + case CP0_REG08__BADINSTR: /* ignored */ register_name = "BadInstr"; break; - case 2: + case CP0_REG08__BADINSTRP: /* ignored */ register_name = "BadInstrP"; break; - case 3: + case CP0_REG08__BADINSTRX: /* ignored */ register_name = "BadInstrX"; break; @@ -9307,16 +9331,16 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_09: switch (sel) { - case 0: + case CP0_REG09__COUNT: gen_helper_mtc0_count(cpu_env, arg); register_name = "Count"; break; - case 6: + case CP0_REG09__SAARI: CP0_CHECK(ctx->saar); gen_helper_mtc0_saari(cpu_env, arg); register_name = "SAARI"; break; - case 7: + case CP0_REG09__SAAR: CP0_CHECK(ctx->saar); gen_helper_mtc0_saar(cpu_env, arg); register_name = "SAAR"; @@ -9329,7 +9353,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_10: switch (sel) { - case 0: + case CP0_REG10__ENTRYHI: gen_helper_mtc0_entryhi(cpu_env, arg); register_name = "EntryHi"; break; @@ -9339,7 +9363,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_11: switch (sel) { - case 0: + case CP0_REG11__COMPARE: gen_helper_mtc0_compare(cpu_env, arg); register_name = "Compare"; break; @@ -9352,7 +9376,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_12: switch (sel) { - case 0: + case CP0_REG12__STATUS: save_cpu_state(ctx, 1); gen_helper_mtc0_status(cpu_env, arg); /* DISAS_STOP isn't good enough here, hflags may have changed. */ @@ -9360,21 +9384,21 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) ctx->base.is_jmp = DISAS_EXIT; register_name = "Status"; break; - case 1: + case CP0_REG12__INTCTL: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_intctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "IntCtl"; break; - case 2: + case CP0_REG12__SRSCTL: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "SRSCtl"; break; - case 3: + case CP0_REG12__SRSMAP: check_insn(ctx, ISA_MIPS32R2); gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap)); /* Stop translation as we may have switched the execution mode */ @@ -9387,7 +9411,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_13: switch (sel) { - case 0: + case CP0_REG13__CAUSE: save_cpu_state(ctx, 1); gen_helper_mtc0_cause(cpu_env, arg); /* @@ -9405,7 +9429,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_14: switch (sel) { - case 0: + case CP0_REG14__EPC: tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC)); register_name = "EPC"; break; @@ -9415,11 +9439,11 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_15: switch (sel) { - case 0: + case CP0_REG15__PRID: /* ignored */ register_name = "PRid"; break; - case 1: + case CP0_REG15__EBASE: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_ebase(cpu_env, arg); register_name = "EBase"; @@ -9430,33 +9454,33 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_16: switch (sel) { - case 0: + case CP0_REG16__CONFIG: gen_helper_mtc0_config0(cpu_env, arg); register_name = "Config"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; break; - case 1: + case CP0_REG16__CONFIG1: /* ignored, read only */ register_name = "Config1"; break; - case 2: + case CP0_REG16__CONFIG2: gen_helper_mtc0_config2(cpu_env, arg); register_name = "Config2"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; break; - case 3: + case CP0_REG16__CONFIG3: gen_helper_mtc0_config3(cpu_env, arg); register_name = "Config3"; /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; break; - case 4: + case CP0_REG16__CONFIG4: /* currently ignored */ register_name = "Config4"; break; - case 5: + case CP0_REG16__CONFIG5: gen_helper_mtc0_config5(cpu_env, arg); register_name = "Config5"; /* Stop translation as we may have switched the execution mode */ @@ -9470,16 +9494,16 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_17: switch (sel) { - case 0: + case CP0_REG17__LLADDR: gen_helper_mtc0_lladdr(cpu_env, arg); register_name = "LLAddr"; break; - case 1: + case CP0_REG17__MAAR: CP0_CHECK(ctx->mrp); gen_helper_mtc0_maar(cpu_env, arg); register_name = "MAAR"; break; - case 2: + case CP0_REG17__MAARI: CP0_CHECK(ctx->mrp); gen_helper_mtc0_maari(cpu_env, arg); register_name = "MAARI"; @@ -9490,14 +9514,14 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_18: switch (sel) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG18__WATCHLO0: + case CP0_REG18__WATCHLO1: + case CP0_REG18__WATCHLO2: + case CP0_REG18__WATCHLO3: + case CP0_REG18__WATCHLO4: + case CP0_REG18__WATCHLO5: + case CP0_REG18__WATCHLO6: + case CP0_REG18__WATCHLO7: CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR)); gen_helper_0e1i(mtc0_watchlo, arg, sel); register_name = "WatchLo"; @@ -9508,14 +9532,14 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_19: switch (sel) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG19__WATCHHI0: + case CP0_REG19__WATCHHI1: + case CP0_REG19__WATCHHI2: + case CP0_REG19__WATCHHI3: + case CP0_REG19__WATCHHI4: + case CP0_REG19__WATCHHI5: + case CP0_REG19__WATCHHI6: + case CP0_REG19__WATCHHI7: CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR)); gen_helper_0e1i(mtc0_watchhi, arg, sel); register_name = "WatchHi"; @@ -9526,7 +9550,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_20: switch (sel) { - case 0: + case CP0_REG20__XCONTEXT: check_insn(ctx, ISA_MIPS3); gen_helper_mtc0_xcontext(cpu_env, arg); register_name = "XContext"; @@ -9553,36 +9577,47 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_23: switch (sel) { - case 0: + case CP0_REG23__DEBUG: gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */ /* DISAS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->base.pc_next + 4); ctx->base.is_jmp = DISAS_EXIT; register_name = "Debug"; break; - case 1: -// gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */ + case CP0_REG23__TRACECONTROL: + /* PDtrace support */ + /* gen_helper_mtc0_tracecontrol(cpu_env, arg); */ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "TraceControl"; goto cp0_unimplemented; - case 2: -// gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */ + case CP0_REG23__TRACECONTROL2: + /* PDtrace support */ + /* gen_helper_mtc0_tracecontrol2(cpu_env, arg); */ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; register_name = "TraceControl2"; goto cp0_unimplemented; - case 3: -// gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */ + case CP0_REG23__USERTRACEDATA1: + /* PDtrace support */ + /* gen_helper_mtc0_usertracedata1(cpu_env, arg);*/ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; - register_name = "UserTraceData"; + register_name = "UserTraceData1"; goto cp0_unimplemented; - case 4: -// gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */ + case CP0_REG23__TRACEIBPC: + /* PDtrace support */ + /* gen_helper_mtc0_traceibpc(cpu_env, arg); */ /* Stop translation as we may have switched the execution mode */ ctx->base.is_jmp = DISAS_STOP; - register_name = "TraceBPC"; + register_name = "TraceIBPC"; + goto cp0_unimplemented; + case CP0_REG23__TRACEDBPC: + /* PDtrace support */ + /* gen_helper_mtc0_tracedbpc(cpu_env, arg); */ + /* Stop translation as we may have switched the execution mode */ + ctx->base.is_jmp = DISAS_STOP; + register_name = "TraceDBPC"; goto cp0_unimplemented; default: goto cp0_unimplemented; @@ -9590,7 +9625,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_24: switch (sel) { - case 0: + case CP0_REG24__DEPC: /* EJTAG support */ tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC)); register_name = "DEPC"; @@ -9601,35 +9636,35 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_25: switch (sel) { - case 0: + case CP0_REG25__PERFCTL0: gen_helper_mtc0_performance0(cpu_env, arg); register_name = "Performance0"; break; - case 1: + case CP0_REG25__PERFCNT0: /* gen_helper_mtc0_performance1(cpu_env, arg); */ register_name = "Performance1"; goto cp0_unimplemented; - case 2: + case CP0_REG25__PERFCTL1: /* gen_helper_mtc0_performance2(cpu_env, arg); */ register_name = "Performance2"; goto cp0_unimplemented; - case 3: + case CP0_REG25__PERFCNT1: /* gen_helper_mtc0_performance3(cpu_env, arg); */ register_name = "Performance3"; goto cp0_unimplemented; - case 4: + case CP0_REG25__PERFCTL2: /* gen_helper_mtc0_performance4(cpu_env, arg); */ register_name = "Performance4"; goto cp0_unimplemented; - case 5: + case CP0_REG25__PERFCNT2: /* gen_helper_mtc0_performance5(cpu_env, arg); */ register_name = "Performance5"; goto cp0_unimplemented; - case 6: + case CP0_REG25__PERFCTL3: /* gen_helper_mtc0_performance6(cpu_env, arg); */ register_name = "Performance6"; goto cp0_unimplemented; - case 7: + case CP0_REG25__PERFCNT3: /* gen_helper_mtc0_performance7(cpu_env, arg); */ register_name = "Performance7"; goto cp0_unimplemented; @@ -9639,7 +9674,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_26: switch (sel) { - case 0: + case CP0_REG26__ERRCTL: gen_helper_mtc0_errctl(cpu_env, arg); ctx->base.is_jmp = DISAS_STOP; register_name = "ErrCtl"; @@ -9650,10 +9685,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_27: switch (sel) { - case 0: - case 1: - case 2: - case 3: + case CP0_REG27__CACHERR: /* ignored */ register_name = "CacheErr"; break; @@ -9663,17 +9695,17 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_28: switch (sel) { - case 0: - case 2: - case 4: - case 6: + case CP0_REG28__TAGLO: + case CP0_REG28__TAGLO1: + case CP0_REG28__TAGLO2: + case CP0_REG28__TAGLO3: gen_helper_mtc0_taglo(cpu_env, arg); register_name = "TagLo"; break; - case 1: - case 3: - case 5: - case 7: + case CP0_REG28__DATALO: + case CP0_REG28__DATALO1: + case CP0_REG28__DATALO2: + case CP0_REG28__DATALO3: gen_helper_mtc0_datalo(cpu_env, arg); register_name = "DataLo"; break; @@ -9683,17 +9715,17 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_29: switch (sel) { - case 0: - case 2: - case 4: - case 6: + case CP0_REG29__TAGHI: + case CP0_REG29__TAGHI1: + case CP0_REG29__TAGHI2: + case CP0_REG29__TAGHI3: gen_helper_mtc0_taghi(cpu_env, arg); register_name = "TagHi"; break; - case 1: - case 3: - case 5: - case 7: + case CP0_REG29__DATAHI: + case CP0_REG29__DATAHI1: + case CP0_REG29__DATAHI2: + case CP0_REG29__DATAHI3: gen_helper_mtc0_datahi(cpu_env, arg); register_name = "DataHi"; break; @@ -9704,7 +9736,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_30: switch (sel) { - case 0: + case CP0_REG30__ERROREPC: tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC)); register_name = "ErrorEPC"; break; @@ -9714,17 +9746,17 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REGISTER_31: switch (sel) { - case 0: + case CP0_REG31__DESAVE: /* EJTAG support */ gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_DESAVE)); register_name = "DESAVE"; break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case CP0_REG31__KSCRATCH1: + case CP0_REG31__KSCRATCH2: + case CP0_REG31__KSCRATCH3: + case CP0_REG31__KSCRATCH4: + case CP0_REG31__KSCRATCH5: + case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_KScratch[sel - 2])); @@ -21827,7 +21859,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) extract32(ctx->opcode, 0, 8); TCGv va = tcg_temp_new(); TCGv t1 = tcg_temp_new(); - TCGMemOp memop = (extract32(ctx->opcode, 8, 3)) == + MemOp memop = (extract32(ctx->opcode, 8, 3)) == NM_P_LS_UAWM ? MO_UNALN : 0; count = (count == 0) ? 8 : count; diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index f19e482a55..506aec6bfb 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -55,13 +55,7 @@ static void openrisc_cpu_reset(CPUState *s) cpu->env.sr = SR_FO | SR_SM; cpu->env.lock_addr = -1; s->exception_index = -1; - - cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP | - UPR_PMP; - cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) - | (DMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2)); - cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) - | (IMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2)); + cpu_set_fpcsr(&cpu->env, 0); #ifndef CONFIG_USER_ONLY cpu->env.picmr = 0x00000000; @@ -117,15 +111,35 @@ static void or1200_initfn(Object *obj) { OpenRISCCPU *cpu = OPENRISC_CPU(obj); + cpu->env.vr = 0x13000008; + cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP | UPR_PMP; cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_OF32S | CPUCFGR_EVBARP; + + /* 1Way, TLB_SIZE entries. */ + cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) + | (DMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2)); + cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) + | (IMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2)); } static void openrisc_any_initfn(Object *obj) { OpenRISCCPU *cpu = OPENRISC_CPU(obj); - cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_EVBARP; + cpu->env.vr = 0x13000040; /* Obsolete VER + UVRP for new SPRs */ + cpu->env.vr2 = 0; /* No version specific id */ + cpu->env.avr = 0x01030000; /* Architecture v1.3 */ + + cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP | UPR_PMP; + cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_OF32S | + CPUCFGR_AVRP | CPUCFGR_EVBARP | CPUCFGR_OF64A32S; + + /* 1Way, TLB_SIZE entries. */ + cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) + | (DMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2)); + cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) + | (IMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2)); } static void openrisc_cpu_class_init(ObjectClass *oc, void *data) diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 561f0f7fad..0ad02eab79 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -68,9 +68,6 @@ enum { (reg) |= ((v & 0x1f) << 2);\ } while (0) -/* Version Register */ -#define SPR_VR 0xFFFF003F - /* Interrupt */ #define NR_IRQS 32 @@ -99,11 +96,12 @@ enum { CPUCFGR_OF32S = (1 << 7), CPUCFGR_OF64S = (1 << 8), CPUCFGR_OV64S = (1 << 9), - /* CPUCFGR_ND = (1 << 10), */ - /* CPUCFGR_AVRP = (1 << 11), */ + CPUCFGR_ND = (1 << 10), + CPUCFGR_AVRP = (1 << 11), CPUCFGR_EVBARP = (1 << 12), - /* CPUCFGR_ISRP = (1 << 13), */ - /* CPUCFGR_AECSRP = (1 << 14), */ + CPUCFGR_ISRP = (1 << 13), + CPUCFGR_AECSRP = (1 << 14), + CPUCFGR_OF64A32S = (1 << 15), }; /* DMMU configure register */ @@ -263,10 +261,6 @@ typedef struct CPUOpenRISCState { target_ulong sr_cy; /* the SR_CY bit, values 0, 1. */ target_long sr_ov; /* the SR_OV bit (in the sign bit only) */ uint32_t sr; /* Supervisor register, without SR_{F,CY,OV} */ - uint32_t vr; /* Version register */ - uint32_t upr; /* Unit presence register */ - uint32_t dmmucfgr; /* DMMU configure register */ - uint32_t immucfgr; /* IMMU configure register */ uint32_t esr; /* Exception supervisor register */ uint32_t evbar; /* Exception vector base address register */ uint32_t pmr; /* Power Management Register */ @@ -286,7 +280,13 @@ typedef struct CPUOpenRISCState { struct {} end_reset_fields; /* Fields from here on are preserved across CPU reset. */ + uint32_t vr; /* Version register */ + uint32_t vr2; /* Version register 2 */ + uint32_t avr; /* Architecture version register */ + uint32_t upr; /* Unit presence register */ uint32_t cpucfgr; /* CPU configure register */ + uint32_t dmmucfgr; /* DMMU configure register */ + uint32_t immucfgr; /* IMMU configure register */ #ifndef CONFIG_USER_ONLY QEMUTimer *timer; @@ -413,6 +413,8 @@ static inline void cpu_set_sr(CPUOpenRISCState *env, uint32_t val) env->sr = (val & ~(SR_F | SR_CY | SR_OV)) | SR_FO; } +void cpu_set_fpcsr(CPUOpenRISCState *env, uint32_t val); + #define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0 #endif /* OPENRISC_CPU_H */ diff --git a/target/openrisc/disas.c b/target/openrisc/disas.c index 7091832347..ce112640b9 100644 --- a/target/openrisc/disas.c +++ b/target/openrisc/disas.c @@ -98,6 +98,7 @@ INSN(sw, "%d(r%d), r%d", a->i, a->a, a->b) INSN(sb, "%d(r%d), r%d", a->i, a->a, a->b) INSN(sh, "%d(r%d), r%d", a->i, a->a, a->b) INSN(nop, "") +INSN(adrp, "r%d, %d", a->d, a->i) INSN(addi, "r%d, r%d, %d", a->d, a->a, a->i) INSN(addic, "r%d, r%d, %d", a->d, a->a, a->i) INSN(muli, "r%d, r%d, %d", a->d, a->a, a->i) @@ -166,3 +167,83 @@ FP_INSN(sfgt, s, "r%d, r%d", a->a, a->b) FP_INSN(sfge, s, "r%d, r%d", a->a, a->b) FP_INSN(sflt, s, "r%d, r%d", a->a, a->b) FP_INSN(sfle, s, "r%d, r%d", a->a, a->b) +FP_INSN(sfun, s, "r%d, r%d", a->a, a->b) +FP_INSN(sfueq, s, "r%d, r%d", a->a, a->b) +FP_INSN(sfuge, s, "r%d, r%d", a->a, a->b) +FP_INSN(sfugt, s, "r%d, r%d", a->a, a->b) +FP_INSN(sfule, s, "r%d, r%d", a->a, a->b) +FP_INSN(sfult, s, "r%d, r%d", a->a, a->b) + +FP_INSN(add, d, "r%d,r%d, r%d,r%d, r%d,r%d", + a->d, a->d + a->dp + 1, + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sub, d, "r%d,r%d, r%d,r%d, r%d,r%d", + a->d, a->d + a->dp + 1, + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(mul, d, "r%d,r%d, r%d,r%d, r%d,r%d", + a->d, a->d + a->dp + 1, + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(div, d, "r%d,r%d, r%d,r%d, r%d,r%d", + a->d, a->d + a->dp + 1, + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(rem, d, "r%d,r%d, r%d,r%d, r%d,r%d", + a->d, a->d + a->dp + 1, + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(madd, d, "r%d,r%d, r%d,r%d, r%d,r%d", + a->d, a->d + a->dp + 1, + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) + +FP_INSN(itof, d, "r%d,r%d, r%d,r%d", + a->d, a->d + a->dp + 1, + a->a, a->a + a->ap + 1) +FP_INSN(ftoi, d, "r%d,r%d, r%d,r%d", + a->d, a->d + a->dp + 1, + a->a, a->a + a->ap + 1) + +FP_INSN(stod, d, "r%d,r%d, r%d", + a->d, a->d + a->dp + 1, a->a) +FP_INSN(dtos, d, "r%d r%d,r%d", + a->d, a->a, a->a + a->ap + 1) + +FP_INSN(sfeq, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sfne, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sfgt, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sfge, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sflt, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sfle, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sfun, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sfueq, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sfuge, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sfugt, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sfule, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) +FP_INSN(sfult, d, "r%d,r%d, r%d,r%d", + a->a, a->a + a->ap + 1, + a->b, a->b + a->bp + 1) diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index b9d2ebbb8c..59e1413279 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -61,9 +61,22 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) } } +void cpu_set_fpcsr(CPUOpenRISCState *env, uint32_t val) +{ + static const int rm_to_sf[] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down + }; + + env->fpcsr = val & 0x7ff; + set_float_rounding_mode(rm_to_sf[extract32(val, 1, 2)], &env->fp_status); +} + uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val) { - return int32_to_float64(val, &env->fp_status); + return int64_to_float64(val, &env->fp_status); } uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val) @@ -73,12 +86,22 @@ uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val) uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val) { - return float32_to_int64(val, &env->fp_status); + return float64_to_int64_round_to_zero(val, &env->fp_status); } uint32_t HELPER(ftois)(CPUOpenRISCState *env, uint32_t val) { - return float32_to_int32(val, &env->fp_status); + return float32_to_int32_round_to_zero(val, &env->fp_status); +} + +uint64_t HELPER(stod)(CPUOpenRISCState *env, uint32_t val) +{ + return float32_to_float64(val, &env->fp_status); +} + +uint32_t HELPER(dtos)(CPUOpenRISCState *env, uint64_t val) +{ + return float64_to_float32(val, &env->fp_status); } #define FLOAT_CALC(name) \ @@ -125,4 +148,24 @@ target_ulong helper_float_ ## name ## _s(CPUOpenRISCState *env, \ FLOAT_CMP(le, le) FLOAT_CMP(lt, lt) FLOAT_CMP(eq, eq_quiet) +FLOAT_CMP(un, unordered_quiet) #undef FLOAT_CMP + +#define FLOAT_UCMP(name, expr) \ +target_ulong helper_float_ ## name ## _d(CPUOpenRISCState *env, \ + uint64_t fdt0, uint64_t fdt1) \ +{ \ + int r = float64_compare_quiet(fdt0, fdt1, &env->fp_status); \ + return expr; \ +} \ +target_ulong helper_float_ ## name ## _s(CPUOpenRISCState *env, \ + uint32_t fdt0, uint32_t fdt1) \ +{ \ + int r = float32_compare_quiet(fdt0, fdt1, &env->fp_status); \ + return expr; \ +} + +FLOAT_UCMP(ueq, r == float_relation_equal || r == float_relation_unordered) +FLOAT_UCMP(ult, r == float_relation_less || r == float_relation_unordered) +FLOAT_UCMP(ule, r != float_relation_greater) +#undef FLOAT_UCMP diff --git a/target/openrisc/helper.h b/target/openrisc/helper.h index 96d79a8113..d847814a28 100644 --- a/target/openrisc/helper.h +++ b/target/openrisc/helper.h @@ -30,6 +30,8 @@ DEF_HELPER_FLAGS_2(itofd, TCG_CALL_NO_RWG, i64, env, i64) DEF_HELPER_FLAGS_2(itofs, TCG_CALL_NO_RWG, i32, env, i32) DEF_HELPER_FLAGS_2(ftoid, TCG_CALL_NO_RWG, i64, env, i64) DEF_HELPER_FLAGS_2(ftois, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(stod, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(dtos, TCG_CALL_NO_RWG, i32, env, i64) DEF_HELPER_FLAGS_4(float_madd_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32) DEF_HELPER_FLAGS_4(float_madd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) @@ -50,6 +52,10 @@ DEF_HELPER_FLAGS_3(float_ ## op ## _d, TCG_CALL_NO_RWG, tl, env, i64, i64) FOP_CMP(eq) FOP_CMP(lt) FOP_CMP(le) +FOP_CMP(un) +FOP_CMP(ueq) +FOP_CMP(ule) +FOP_CMP(ult) #undef FOP_CMP /* interrupt */ diff --git a/target/openrisc/insns.decode b/target/openrisc/insns.decode index 7df81c1f22..0d6f7c29f8 100644 --- a/target/openrisc/insns.decode +++ b/target/openrisc/insns.decode @@ -22,6 +22,9 @@ &ab a b &dal d a l &ai a i +&dab_pair d a b dp ap bp +&ab_pair a b ap bp +&da_pair d a dp ap #### # System Instructions @@ -99,6 +102,8 @@ l_maci 010011 ----- a:5 i:s16 l_movhi 000110 d:5 ----0 k:16 l_macrc 000110 d:5 ----1 00000000 00000000 +l_adrp 000010 d:5 i:s21 + #### # Arithmetic Instructions #### @@ -187,3 +192,43 @@ lf_sfgt_s 110010 ----- a:5 b:5 --- 00001010 lf_sfge_s 110010 ----- a:5 b:5 --- 00001011 lf_sflt_s 110010 ----- a:5 b:5 --- 00001100 lf_sfle_s 110010 ----- a:5 b:5 --- 00001101 +lf_sfueq_s 110010 ----- a:5 b:5 --- 00101000 +lf_sfuge_s 110010 ----- a:5 b:5 --- 00101011 +lf_sfugt_s 110010 ----- a:5 b:5 --- 00101010 +lf_sfule_s 110010 ----- a:5 b:5 --- 00101101 +lf_sfult_s 110010 ----- a:5 b:5 --- 00101100 +lf_sfun_s 110010 ----- a:5 b:5 --- 00101110 + +#### +# DP Instructions +#### + +@dab_pair ...... d:5 a:5 b:5 dp:1 ap:1 bp:1 ........ &dab_pair +@ab_pair ...... ..... a:5 b:5 . ap:1 bp:1 ........ &ab_pair +@da_pair ...... d:5 a:5 ..... dp:1 ap:1 . ........ &da_pair + +lf_add_d 110010 ..... ..... ..... ... 00010000 @dab_pair +lf_sub_d 110010 ..... ..... ..... ... 00010001 @dab_pair +lf_mul_d 110010 ..... ..... ..... ... 00010010 @dab_pair +lf_div_d 110010 ..... ..... ..... ... 00010011 @dab_pair +lf_rem_d 110010 ..... ..... ..... ... 00010110 @dab_pair +lf_madd_d 110010 ..... ..... ..... ... 00010111 @dab_pair + +lf_itof_d 110010 ..... ..... 00000 ..0 00010100 @da_pair +lf_ftoi_d 110010 ..... ..... 00000 ..0 00010101 @da_pair + +lf_stod_d 110010 d:5 a:5 00000 dp:1 0 0 00110100 +lf_dtos_d 110010 d:5 a:5 00000 0 ap:1 0 00110101 + +lf_sfeq_d 110010 00000 ..... ..... 0.. 00011000 @ab_pair +lf_sfne_d 110010 00000 ..... ..... 0.. 00011001 @ab_pair +lf_sfgt_d 110010 00000 ..... ..... 0.. 00011010 @ab_pair +lf_sfge_d 110010 00000 ..... ..... 0.. 00011011 @ab_pair +lf_sflt_d 110010 00000 ..... ..... 0.. 00011100 @ab_pair +lf_sfle_d 110010 00000 ..... ..... 0.. 00011101 @ab_pair +lf_sfueq_d 110010 00000 ..... ..... 0.. 00111000 @ab_pair +lf_sfuge_d 110010 00000 ..... ..... 0.. 00111011 @ab_pair +lf_sfugt_d 110010 00000 ..... ..... 0.. 00111010 @ab_pair +lf_sfule_d 110010 00000 ..... ..... 0.. 00111101 @ab_pair +lf_sfult_d 110010 00000 ..... ..... 0.. 00111100 @ab_pair +lf_sfun_d 110010 00000 ..... ..... 0.. 00111110 @ab_pair diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c index 0a96404dc6..b92985d99b 100644 --- a/target/openrisc/machine.c +++ b/target/openrisc/machine.c @@ -121,10 +121,21 @@ static const VMStateDescription vmstate_env = { } }; +static int cpu_post_load(void *opaque, int version_id) +{ + OpenRISCCPU *cpu = opaque; + CPUOpenRISCState *env = &cpu->env; + + /* Update env->fp_status to match env->fpcsr. */ + cpu_set_fpcsr(env, env->fpcsr); + return 0; +} + const VMStateDescription vmstate_openrisc_cpu = { .name = "cpu", .version_id = 1, .minimum_version_id = 1, + .post_load = cpu_post_load, .fields = (VMStateField[]) { VMSTATE_CPU(), VMSTATE_STRUCT(env, OpenRISCCPU, 1, vmstate_env, CPUOpenRISCState), diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 1053409a04..d9fe6c5948 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -37,12 +37,10 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) CPUState *cs = env_cpu(env); target_ulong mr; int idx; +#endif switch (spr) { - case TO_SPR(0, 0): /* VR */ - env->vr = rb; - break; - +#ifndef CONFIG_USER_ONLY case TO_SPR(0, 11): /* EVBAR */ env->evbar = rb; break; @@ -62,10 +60,6 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) cpu_set_sr(env, rb); break; - case TO_SPR(0, 18): /* PPC */ - env->ppc = rb; - break; - case TO_SPR(0, 32): /* EPCR */ env->epcr = rb; break; @@ -187,10 +181,12 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) } cpu_openrisc_timer_update(cpu); break; - default: +#endif + + case TO_SPR(0, 20): /* FPCSR */ + cpu_set_fpcsr(env, rb); break; } -#endif } target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, @@ -201,23 +197,31 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, OpenRISCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); int idx; +#endif switch (spr) { +#ifndef CONFIG_USER_ONLY case TO_SPR(0, 0): /* VR */ - return env->vr & SPR_VR; + return env->vr; case TO_SPR(0, 1): /* UPR */ - return env->upr; /* TT, DM, IM, UP present */ + return env->upr; case TO_SPR(0, 2): /* CPUCFGR */ return env->cpucfgr; case TO_SPR(0, 3): /* DMMUCFGR */ - return env->dmmucfgr; /* 1Way, 64 entries */ + return env->dmmucfgr; case TO_SPR(0, 4): /* IMMUCFGR */ return env->immucfgr; + case TO_SPR(0, 9): /* VR2 */ + return env->vr2; + + case TO_SPR(0, 10): /* AVR */ + return env->avr; + case TO_SPR(0, 11): /* EVBAR */ return env->evbar; @@ -305,11 +309,11 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, case TO_SPR(10, 1): /* TTCR */ cpu_openrisc_count_update(cpu); return cpu_openrisc_count_get(cpu); +#endif - default: - break; + case TO_SPR(0, 20): /* FPCSR */ + return env->fpcsr; } -#endif /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 4360ce4045..6addbac8d6 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -45,9 +45,14 @@ typedef struct DisasContext { uint32_t mem_idx; uint32_t tb_flags; uint32_t delayed_branch; + uint32_t cpucfgr; + uint32_t avr; /* If not -1, jmp_pc contains this value and so is a direct jump. */ target_ulong jmp_pc_imm; + + /* The temporary corresponding to register 0 for this compilation. */ + TCGv R0; } DisasContext; static inline bool is_user(DisasContext *dc) @@ -63,8 +68,7 @@ static inline bool is_user(DisasContext *dc) #include "decode.inc.c" static TCGv cpu_sr; -static TCGv cpu_R[32]; -static TCGv cpu_R0; +static TCGv cpu_regs[32]; static TCGv cpu_pc; static TCGv jmp_pc; /* l.jr/l.jalr temp pc */ static TCGv cpu_ppc; @@ -117,12 +121,11 @@ void openrisc_translate_init(void) offsetof(CPUOpenRISCState, mac), "mac"); for (i = 0; i < 32; i++) { - cpu_R[i] = tcg_global_mem_new(cpu_env, - offsetof(CPUOpenRISCState, - shadow_gpr[0][i]), - regnames[i]); + cpu_regs[i] = tcg_global_mem_new(cpu_env, + offsetof(CPUOpenRISCState, + shadow_gpr[0][i]), + regnames[i]); } - cpu_R0 = cpu_R[0]; } static void gen_exception(DisasContext *dc, unsigned int excp) @@ -139,38 +142,40 @@ static void gen_illegal_exception(DisasContext *dc) dc->base.is_jmp = DISAS_NORETURN; } -/* not used yet, open it when we need or64. */ -/*#ifdef TARGET_OPENRISC64 -static void check_ob64s(DisasContext *dc) +static bool check_v1_3(DisasContext *dc) { - if (!(dc->flags & CPUCFGR_OB64S)) { - gen_illegal_exception(dc); - } + return dc->avr >= 0x01030000; } -static void check_of64s(DisasContext *dc) +static bool check_of32s(DisasContext *dc) { - if (!(dc->flags & CPUCFGR_OF64S)) { - gen_illegal_exception(dc); - } + return dc->cpucfgr & CPUCFGR_OF32S; } -static void check_ov64s(DisasContext *dc) +static bool check_of64a32s(DisasContext *dc) { - if (!(dc->flags & CPUCFGR_OV64S)) { - gen_illegal_exception(dc); + return dc->cpucfgr & CPUCFGR_OF64A32S; +} + +static TCGv cpu_R(DisasContext *dc, int reg) +{ + if (reg == 0) { + return dc->R0; + } else { + return cpu_regs[reg]; } } -#endif*/ -/* We're about to write to REG. On the off-chance that the user is - writing to R0, re-instate the architectural register. */ -#define check_r0_write(reg) \ - do { \ - if (unlikely(reg == 0)) { \ - cpu_R[0] = cpu_R0; \ - } \ - } while (0) +/* + * We're about to write to REG. On the off-chance that the user is + * writing to R0, re-instate the architectural register. + */ +static void check_r0_write(DisasContext *dc, int reg) +{ + if (unlikely(reg == 0)) { + dc->R0 = cpu_regs[0]; + } +} static void gen_ove_cy(DisasContext *dc) { @@ -436,99 +441,99 @@ static void gen_msbu(DisasContext *dc, TCGv srca, TCGv srcb) static bool trans_l_add(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - gen_add(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + gen_add(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_addc(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - gen_addc(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + gen_addc(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sub(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - gen_sub(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + gen_sub(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_and(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - tcg_gen_and_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + tcg_gen_and_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_or(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - tcg_gen_or_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + tcg_gen_or_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_xor(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - tcg_gen_xor_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + tcg_gen_xor_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sll(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - tcg_gen_shl_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + tcg_gen_shl_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_srl(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - tcg_gen_shr_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + tcg_gen_shr_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sra(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - tcg_gen_sar_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + tcg_gen_sar_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_ror(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - tcg_gen_rotr_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + tcg_gen_rotr_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_exths(DisasContext *dc, arg_da *a) { - check_r0_write(a->d); - tcg_gen_ext16s_tl(cpu_R[a->d], cpu_R[a->a]); + check_r0_write(dc, a->d); + tcg_gen_ext16s_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); return true; } static bool trans_l_extbs(DisasContext *dc, arg_da *a) { - check_r0_write(a->d); - tcg_gen_ext8s_tl(cpu_R[a->d], cpu_R[a->a]); + check_r0_write(dc, a->d); + tcg_gen_ext8s_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); return true; } static bool trans_l_exthz(DisasContext *dc, arg_da *a) { - check_r0_write(a->d); - tcg_gen_ext16u_tl(cpu_R[a->d], cpu_R[a->a]); + check_r0_write(dc, a->d); + tcg_gen_ext16u_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); return true; } static bool trans_l_extbz(DisasContext *dc, arg_da *a) { - check_r0_write(a->d); - tcg_gen_ext8u_tl(cpu_R[a->d], cpu_R[a->a]); + check_r0_write(dc, a->d); + tcg_gen_ext8u_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); return true; } @@ -536,67 +541,67 @@ static bool trans_l_cmov(DisasContext *dc, arg_dab *a) { TCGv zero; - check_r0_write(a->d); + check_r0_write(dc, a->d); zero = tcg_const_tl(0); - tcg_gen_movcond_tl(TCG_COND_NE, cpu_R[a->d], cpu_sr_f, zero, - cpu_R[a->a], cpu_R[a->b]); + tcg_gen_movcond_tl(TCG_COND_NE, cpu_R(dc, a->d), cpu_sr_f, zero, + cpu_R(dc, a->a), cpu_R(dc, a->b)); tcg_temp_free(zero); return true; } static bool trans_l_ff1(DisasContext *dc, arg_da *a) { - check_r0_write(a->d); - tcg_gen_ctzi_tl(cpu_R[a->d], cpu_R[a->a], -1); - tcg_gen_addi_tl(cpu_R[a->d], cpu_R[a->d], 1); + check_r0_write(dc, a->d); + tcg_gen_ctzi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), -1); + tcg_gen_addi_tl(cpu_R(dc, a->d), cpu_R(dc, a->d), 1); return true; } static bool trans_l_fl1(DisasContext *dc, arg_da *a) { - check_r0_write(a->d); - tcg_gen_clzi_tl(cpu_R[a->d], cpu_R[a->a], TARGET_LONG_BITS); - tcg_gen_subfi_tl(cpu_R[a->d], TARGET_LONG_BITS, cpu_R[a->d]); + check_r0_write(dc, a->d); + tcg_gen_clzi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), TARGET_LONG_BITS); + tcg_gen_subfi_tl(cpu_R(dc, a->d), TARGET_LONG_BITS, cpu_R(dc, a->d)); return true; } static bool trans_l_mul(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - gen_mul(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + gen_mul(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_mulu(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - gen_mulu(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + gen_mulu(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_div(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - gen_div(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + gen_div(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_divu(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - gen_divu(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]); + check_r0_write(dc, a->d); + gen_divu(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_muld(DisasContext *dc, arg_ab *a) { - gen_muld(dc, cpu_R[a->a], cpu_R[a->b]); + gen_muld(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_muldu(DisasContext *dc, arg_ab *a) { - gen_muldu(dc, cpu_R[a->a], cpu_R[a->b]); + gen_muldu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } @@ -615,7 +620,7 @@ static bool trans_l_jal(DisasContext *dc, arg_l_jal *a) target_ulong tmp_pc = dc->base.pc_next + a->n * 4; target_ulong ret_pc = dc->base.pc_next + 8; - tcg_gen_movi_tl(cpu_R[9], ret_pc); + tcg_gen_movi_tl(cpu_regs[9], ret_pc); /* Optimize jal being used to load the PC for PIC. */ if (tmp_pc != ret_pc) { tcg_gen_movi_tl(jmp_pc, tmp_pc); @@ -654,15 +659,15 @@ static bool trans_l_bnf(DisasContext *dc, arg_l_bf *a) static bool trans_l_jr(DisasContext *dc, arg_l_jr *a) { - tcg_gen_mov_tl(jmp_pc, cpu_R[a->b]); + tcg_gen_mov_tl(jmp_pc, cpu_R(dc, a->b)); dc->delayed_branch = 2; return true; } static bool trans_l_jalr(DisasContext *dc, arg_l_jalr *a) { - tcg_gen_mov_tl(jmp_pc, cpu_R[a->b]); - tcg_gen_movi_tl(cpu_R[9], dc->base.pc_next + 8); + tcg_gen_mov_tl(jmp_pc, cpu_R(dc, a->b)); + tcg_gen_movi_tl(cpu_regs[9], dc->base.pc_next + 8); dc->delayed_branch = 2; return true; } @@ -671,24 +676,24 @@ static bool trans_l_lwa(DisasContext *dc, arg_load *a) { TCGv ea; - check_r0_write(a->d); + check_r0_write(dc, a->d); ea = tcg_temp_new(); - tcg_gen_addi_tl(ea, cpu_R[a->a], a->i); - tcg_gen_qemu_ld_tl(cpu_R[a->d], ea, dc->mem_idx, MO_TEUL); + tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i); + tcg_gen_qemu_ld_tl(cpu_R(dc, a->d), ea, dc->mem_idx, MO_TEUL); tcg_gen_mov_tl(cpu_lock_addr, ea); - tcg_gen_mov_tl(cpu_lock_value, cpu_R[a->d]); + tcg_gen_mov_tl(cpu_lock_value, cpu_R(dc, a->d)); tcg_temp_free(ea); return true; } -static void do_load(DisasContext *dc, arg_load *a, TCGMemOp mop) +static void do_load(DisasContext *dc, arg_load *a, MemOp mop) { TCGv ea; - check_r0_write(a->d); + check_r0_write(dc, a->d); ea = tcg_temp_new(); - tcg_gen_addi_tl(ea, cpu_R[a->a], a->i); - tcg_gen_qemu_ld_tl(cpu_R[a->d], ea, dc->mem_idx, mop); + tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i); + tcg_gen_qemu_ld_tl(cpu_R(dc, a->d), ea, dc->mem_idx, mop); tcg_temp_free(ea); } @@ -734,13 +739,13 @@ static bool trans_l_swa(DisasContext *dc, arg_store *a) TCGLabel *lab_fail, *lab_done; ea = tcg_temp_new(); - tcg_gen_addi_tl(ea, cpu_R[a->a], a->i); + tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i); /* For TB_FLAGS_R0_0, the branch below invalidates the temporary assigned - to cpu_R[0]. Since l.swa is quite often immediately followed by a + to cpu_regs[0]. Since l.swa is quite often immediately followed by a branch, don't bother reallocating; finish the TB using the "real" R0. This also takes care of RB input across the branch. */ - cpu_R[0] = cpu_R0; + dc->R0 = cpu_regs[0]; lab_fail = gen_new_label(); lab_done = gen_new_label(); @@ -749,7 +754,7 @@ static bool trans_l_swa(DisasContext *dc, arg_store *a) val = tcg_temp_new(); tcg_gen_atomic_cmpxchg_tl(val, cpu_lock_addr, cpu_lock_value, - cpu_R[a->b], dc->mem_idx, MO_TEUL); + cpu_regs[a->b], dc->mem_idx, MO_TEUL); tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, val, cpu_lock_value); tcg_temp_free(val); @@ -763,11 +768,11 @@ static bool trans_l_swa(DisasContext *dc, arg_store *a) return true; } -static void do_store(DisasContext *dc, arg_store *a, TCGMemOp mop) +static void do_store(DisasContext *dc, arg_store *a, MemOp mop) { TCGv t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[a->a], a->i); - tcg_gen_qemu_st_tl(cpu_R[a->b], t0, dc->mem_idx, mop); + tcg_gen_addi_tl(t0, cpu_R(dc, a->a), a->i); + tcg_gen_qemu_st_tl(cpu_R(dc, a->b), t0, dc->mem_idx, mop); tcg_temp_free(t0); } @@ -794,13 +799,26 @@ static bool trans_l_nop(DisasContext *dc, arg_l_nop *a) return true; } +static bool trans_l_adrp(DisasContext *dc, arg_l_adrp *a) +{ + if (!check_v1_3(dc)) { + return false; + } + check_r0_write(dc, a->d); + + tcg_gen_movi_i32(cpu_R(dc, a->d), + (dc->base.pc_next & TARGET_PAGE_MASK) + + ((target_long)a->i << TARGET_PAGE_BITS)); + return true; +} + static bool trans_l_addi(DisasContext *dc, arg_rri *a) { TCGv t0; - check_r0_write(a->d); + check_r0_write(dc, a->d); t0 = tcg_const_tl(a->i); - gen_add(dc, cpu_R[a->d], cpu_R[a->a], t0); + gen_add(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), t0); tcg_temp_free(t0); return true; } @@ -809,9 +827,9 @@ static bool trans_l_addic(DisasContext *dc, arg_rri *a) { TCGv t0; - check_r0_write(a->d); + check_r0_write(dc, a->d); t0 = tcg_const_tl(a->i); - gen_addc(dc, cpu_R[a->d], cpu_R[a->a], t0); + gen_addc(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), t0); tcg_temp_free(t0); return true; } @@ -820,9 +838,9 @@ static bool trans_l_muli(DisasContext *dc, arg_rri *a) { TCGv t0; - check_r0_write(a->d); + check_r0_write(dc, a->d); t0 = tcg_const_tl(a->i); - gen_mul(dc, cpu_R[a->d], cpu_R[a->a], t0); + gen_mul(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), t0); tcg_temp_free(t0); return true; } @@ -832,42 +850,42 @@ static bool trans_l_maci(DisasContext *dc, arg_l_maci *a) TCGv t0; t0 = tcg_const_tl(a->i); - gen_mac(dc, cpu_R[a->a], t0); + gen_mac(dc, cpu_R(dc, a->a), t0); tcg_temp_free(t0); return true; } static bool trans_l_andi(DisasContext *dc, arg_rrk *a) { - check_r0_write(a->d); - tcg_gen_andi_tl(cpu_R[a->d], cpu_R[a->a], a->k); + check_r0_write(dc, a->d); + tcg_gen_andi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->k); return true; } static bool trans_l_ori(DisasContext *dc, arg_rrk *a) { - check_r0_write(a->d); - tcg_gen_ori_tl(cpu_R[a->d], cpu_R[a->a], a->k); + check_r0_write(dc, a->d); + tcg_gen_ori_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->k); return true; } static bool trans_l_xori(DisasContext *dc, arg_rri *a) { - check_r0_write(a->d); - tcg_gen_xori_tl(cpu_R[a->d], cpu_R[a->a], a->i); + check_r0_write(dc, a->d); + tcg_gen_xori_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->i); return true; } static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) { - check_r0_write(a->d); + check_r0_write(dc, a->d); if (is_user(dc)) { gen_illegal_exception(dc); } else { TCGv spr = tcg_temp_new(); - tcg_gen_ori_tl(spr, cpu_R[a->a], a->k); - gen_helper_mfspr(cpu_R[a->d], cpu_env, cpu_R[a->d], spr); + tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); + gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); tcg_temp_free(spr); } return true; @@ -894,8 +912,8 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) dc->base.is_jmp = DISAS_EXIT; spr = tcg_temp_new(); - tcg_gen_ori_tl(spr, cpu_R[a->a], a->k); - gen_helper_mtspr(cpu_env, spr, cpu_R[a->b]); + tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); + gen_helper_mtspr(cpu_env, spr, cpu_R(dc, a->b)); tcg_temp_free(spr); } return true; @@ -903,188 +921,202 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) static bool trans_l_mac(DisasContext *dc, arg_ab *a) { - gen_mac(dc, cpu_R[a->a], cpu_R[a->b]); + gen_mac(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_msb(DisasContext *dc, arg_ab *a) { - gen_msb(dc, cpu_R[a->a], cpu_R[a->b]); + gen_msb(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_macu(DisasContext *dc, arg_ab *a) { - gen_macu(dc, cpu_R[a->a], cpu_R[a->b]); + gen_macu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_msbu(DisasContext *dc, arg_ab *a) { - gen_msbu(dc, cpu_R[a->a], cpu_R[a->b]); + gen_msbu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_slli(DisasContext *dc, arg_dal *a) { - check_r0_write(a->d); - tcg_gen_shli_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1)); + check_r0_write(dc, a->d); + tcg_gen_shli_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), + a->l & (TARGET_LONG_BITS - 1)); return true; } static bool trans_l_srli(DisasContext *dc, arg_dal *a) { - check_r0_write(a->d); - tcg_gen_shri_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1)); + check_r0_write(dc, a->d); + tcg_gen_shri_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), + a->l & (TARGET_LONG_BITS - 1)); return true; } static bool trans_l_srai(DisasContext *dc, arg_dal *a) { - check_r0_write(a->d); - tcg_gen_sari_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1)); + check_r0_write(dc, a->d); + tcg_gen_sari_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), + a->l & (TARGET_LONG_BITS - 1)); return true; } static bool trans_l_rori(DisasContext *dc, arg_dal *a) { - check_r0_write(a->d); - tcg_gen_rotri_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1)); + check_r0_write(dc, a->d); + tcg_gen_rotri_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), + a->l & (TARGET_LONG_BITS - 1)); return true; } static bool trans_l_movhi(DisasContext *dc, arg_l_movhi *a) { - check_r0_write(a->d); - tcg_gen_movi_tl(cpu_R[a->d], a->k << 16); + check_r0_write(dc, a->d); + tcg_gen_movi_tl(cpu_R(dc, a->d), a->k << 16); return true; } static bool trans_l_macrc(DisasContext *dc, arg_l_macrc *a) { - check_r0_write(a->d); - tcg_gen_trunc_i64_tl(cpu_R[a->d], cpu_mac); + check_r0_write(dc, a->d); + tcg_gen_trunc_i64_tl(cpu_R(dc, a->d), cpu_mac); tcg_gen_movi_i64(cpu_mac, 0); return true; } static bool trans_l_sfeq(DisasContext *dc, arg_ab *a) { - tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]); + tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, + cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sfne(DisasContext *dc, arg_ab *a) { - tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]); + tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_f, + cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sfgtu(DisasContext *dc, arg_ab *a) { - tcg_gen_setcond_tl(TCG_COND_GTU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]); + tcg_gen_setcond_tl(TCG_COND_GTU, cpu_sr_f, + cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sfgeu(DisasContext *dc, arg_ab *a) { - tcg_gen_setcond_tl(TCG_COND_GEU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]); + tcg_gen_setcond_tl(TCG_COND_GEU, cpu_sr_f, + cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sfltu(DisasContext *dc, arg_ab *a) { - tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]); + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_f, + cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sfleu(DisasContext *dc, arg_ab *a) { - tcg_gen_setcond_tl(TCG_COND_LEU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]); + tcg_gen_setcond_tl(TCG_COND_LEU, cpu_sr_f, + cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sfgts(DisasContext *dc, arg_ab *a) { - tcg_gen_setcond_tl(TCG_COND_GT, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]); + tcg_gen_setcond_tl(TCG_COND_GT, cpu_sr_f, + cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sfges(DisasContext *dc, arg_ab *a) { - tcg_gen_setcond_tl(TCG_COND_GE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]); + tcg_gen_setcond_tl(TCG_COND_GE, cpu_sr_f, + cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sflts(DisasContext *dc, arg_ab *a) { - tcg_gen_setcond_tl(TCG_COND_LT, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]); + tcg_gen_setcond_tl(TCG_COND_LT, cpu_sr_f, + cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sfles(DisasContext *dc, arg_ab *a) { - tcg_gen_setcond_tl(TCG_COND_LE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]); + tcg_gen_setcond_tl(TCG_COND_LE, + cpu_sr_f, cpu_R(dc, a->a), cpu_R(dc, a->b)); return true; } static bool trans_l_sfeqi(DisasContext *dc, arg_ai *a) { - tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_f, cpu_R[a->a], a->i); + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_f, cpu_R(dc, a->a), a->i); return true; } static bool trans_l_sfnei(DisasContext *dc, arg_ai *a) { - tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_f, cpu_R[a->a], a->i); + tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_f, cpu_R(dc, a->a), a->i); return true; } static bool trans_l_sfgtui(DisasContext *dc, arg_ai *a) { - tcg_gen_setcondi_tl(TCG_COND_GTU, cpu_sr_f, cpu_R[a->a], a->i); + tcg_gen_setcondi_tl(TCG_COND_GTU, cpu_sr_f, cpu_R(dc, a->a), a->i); return true; } static bool trans_l_sfgeui(DisasContext *dc, arg_ai *a) { - tcg_gen_setcondi_tl(TCG_COND_GEU, cpu_sr_f, cpu_R[a->a], a->i); + tcg_gen_setcondi_tl(TCG_COND_GEU, cpu_sr_f, cpu_R(dc, a->a), a->i); return true; } static bool trans_l_sfltui(DisasContext *dc, arg_ai *a) { - tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_sr_f, cpu_R[a->a], a->i); + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_sr_f, cpu_R(dc, a->a), a->i); return true; } static bool trans_l_sfleui(DisasContext *dc, arg_ai *a) { - tcg_gen_setcondi_tl(TCG_COND_LEU, cpu_sr_f, cpu_R[a->a], a->i); + tcg_gen_setcondi_tl(TCG_COND_LEU, cpu_sr_f, cpu_R(dc, a->a), a->i); return true; } static bool trans_l_sfgtsi(DisasContext *dc, arg_ai *a) { - tcg_gen_setcondi_tl(TCG_COND_GT, cpu_sr_f, cpu_R[a->a], a->i); + tcg_gen_setcondi_tl(TCG_COND_GT, cpu_sr_f, cpu_R(dc, a->a), a->i); return true; } static bool trans_l_sfgesi(DisasContext *dc, arg_ai *a) { - tcg_gen_setcondi_tl(TCG_COND_GE, cpu_sr_f, cpu_R[a->a], a->i); + tcg_gen_setcondi_tl(TCG_COND_GE, cpu_sr_f, cpu_R(dc, a->a), a->i); return true; } static bool trans_l_sfltsi(DisasContext *dc, arg_ai *a) { - tcg_gen_setcondi_tl(TCG_COND_LT, cpu_sr_f, cpu_R[a->a], a->i); + tcg_gen_setcondi_tl(TCG_COND_LT, cpu_sr_f, cpu_R(dc, a->a), a->i); return true; } static bool trans_l_sflesi(DisasContext *dc, arg_ai *a) { - tcg_gen_setcondi_tl(TCG_COND_LE, cpu_sr_f, cpu_R[a->a], a->i); + tcg_gen_setcondi_tl(TCG_COND_LE, cpu_sr_f, cpu_R(dc, a->a), a->i); return true; } @@ -1131,124 +1163,430 @@ static bool trans_l_rfe(DisasContext *dc, arg_l_rfe *a) return true; } -static void do_fp2(DisasContext *dc, arg_da *a, +static bool do_fp2(DisasContext *dc, arg_da *a, void (*fn)(TCGv, TCGv_env, TCGv)) { - check_r0_write(a->d); - fn(cpu_R[a->d], cpu_env, cpu_R[a->a]); + if (!check_of32s(dc)) { + return false; + } + check_r0_write(dc, a->d); + fn(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->a)); gen_helper_update_fpcsr(cpu_env); + return true; } -static void do_fp3(DisasContext *dc, arg_dab *a, +static bool do_fp3(DisasContext *dc, arg_dab *a, void (*fn)(TCGv, TCGv_env, TCGv, TCGv)) { - check_r0_write(a->d); - fn(cpu_R[a->d], cpu_env, cpu_R[a->a], cpu_R[a->b]); + if (!check_of32s(dc)) { + return false; + } + check_r0_write(dc, a->d); + fn(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->a), cpu_R(dc, a->b)); gen_helper_update_fpcsr(cpu_env); + return true; } -static void do_fpcmp(DisasContext *dc, arg_ab *a, +static bool do_fpcmp(DisasContext *dc, arg_ab *a, void (*fn)(TCGv, TCGv_env, TCGv, TCGv), bool inv, bool swap) { + if (!check_of32s(dc)) { + return false; + } if (swap) { - fn(cpu_sr_f, cpu_env, cpu_R[a->b], cpu_R[a->a]); + fn(cpu_sr_f, cpu_env, cpu_R(dc, a->b), cpu_R(dc, a->a)); } else { - fn(cpu_sr_f, cpu_env, cpu_R[a->a], cpu_R[a->b]); + fn(cpu_sr_f, cpu_env, cpu_R(dc, a->a), cpu_R(dc, a->b)); } if (inv) { tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1); } gen_helper_update_fpcsr(cpu_env); + return true; } static bool trans_lf_add_s(DisasContext *dc, arg_dab *a) { - do_fp3(dc, a, gen_helper_float_add_s); - return true; + return do_fp3(dc, a, gen_helper_float_add_s); } static bool trans_lf_sub_s(DisasContext *dc, arg_dab *a) { - do_fp3(dc, a, gen_helper_float_sub_s); - return true; + return do_fp3(dc, a, gen_helper_float_sub_s); } static bool trans_lf_mul_s(DisasContext *dc, arg_dab *a) { - do_fp3(dc, a, gen_helper_float_mul_s); - return true; + return do_fp3(dc, a, gen_helper_float_mul_s); } static bool trans_lf_div_s(DisasContext *dc, arg_dab *a) { - do_fp3(dc, a, gen_helper_float_div_s); - return true; + return do_fp3(dc, a, gen_helper_float_div_s); } static bool trans_lf_rem_s(DisasContext *dc, arg_dab *a) { - do_fp3(dc, a, gen_helper_float_rem_s); + return do_fp3(dc, a, gen_helper_float_rem_s); return true; } static bool trans_lf_itof_s(DisasContext *dc, arg_da *a) { - do_fp2(dc, a, gen_helper_itofs); - return true; + return do_fp2(dc, a, gen_helper_itofs); } static bool trans_lf_ftoi_s(DisasContext *dc, arg_da *a) { - do_fp2(dc, a, gen_helper_ftois); - return true; + return do_fp2(dc, a, gen_helper_ftois); } static bool trans_lf_madd_s(DisasContext *dc, arg_dab *a) { - check_r0_write(a->d); - gen_helper_float_madd_s(cpu_R[a->d], cpu_env, cpu_R[a->d], - cpu_R[a->a], cpu_R[a->b]); + if (!check_of32s(dc)) { + return false; + } + check_r0_write(dc, a->d); + gen_helper_float_madd_s(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), + cpu_R(dc, a->a), cpu_R(dc, a->b)); gen_helper_update_fpcsr(cpu_env); return true; } static bool trans_lf_sfeq_s(DisasContext *dc, arg_ab *a) { - do_fpcmp(dc, a, gen_helper_float_eq_s, false, false); - return true; + return do_fpcmp(dc, a, gen_helper_float_eq_s, false, false); } static bool trans_lf_sfne_s(DisasContext *dc, arg_ab *a) { - do_fpcmp(dc, a, gen_helper_float_eq_s, true, false); - return true; + return do_fpcmp(dc, a, gen_helper_float_eq_s, true, false); } static bool trans_lf_sfgt_s(DisasContext *dc, arg_ab *a) { - do_fpcmp(dc, a, gen_helper_float_lt_s, false, true); - return true; + return do_fpcmp(dc, a, gen_helper_float_lt_s, false, true); } static bool trans_lf_sfge_s(DisasContext *dc, arg_ab *a) { - do_fpcmp(dc, a, gen_helper_float_le_s, false, true); - return true; + return do_fpcmp(dc, a, gen_helper_float_le_s, false, true); } static bool trans_lf_sflt_s(DisasContext *dc, arg_ab *a) { - do_fpcmp(dc, a, gen_helper_float_lt_s, false, false); - return true; + return do_fpcmp(dc, a, gen_helper_float_lt_s, false, false); } static bool trans_lf_sfle_s(DisasContext *dc, arg_ab *a) { - do_fpcmp(dc, a, gen_helper_float_le_s, false, false); + return do_fpcmp(dc, a, gen_helper_float_le_s, false, false); +} + +static bool trans_lf_sfueq_s(DisasContext *dc, arg_ab *a) +{ + if (!check_v1_3(dc)) { + return false; + } + return do_fpcmp(dc, a, gen_helper_float_ueq_s, false, false); +} + +static bool trans_lf_sfult_s(DisasContext *dc, arg_ab *a) +{ + if (!check_v1_3(dc)) { + return false; + } + return do_fpcmp(dc, a, gen_helper_float_ult_s, false, false); +} + +static bool trans_lf_sfugt_s(DisasContext *dc, arg_ab *a) +{ + if (!check_v1_3(dc)) { + return false; + } + return do_fpcmp(dc, a, gen_helper_float_ult_s, false, true); +} + +static bool trans_lf_sfule_s(DisasContext *dc, arg_ab *a) +{ + if (!check_v1_3(dc)) { + return false; + } + return do_fpcmp(dc, a, gen_helper_float_ule_s, false, false); +} + +static bool trans_lf_sfuge_s(DisasContext *dc, arg_ab *a) +{ + if (!check_v1_3(dc)) { + return false; + } + return do_fpcmp(dc, a, gen_helper_float_ule_s, false, true); +} + +static bool trans_lf_sfun_s(DisasContext *dc, arg_ab *a) +{ + if (!check_v1_3(dc)) { + return false; + } + return do_fpcmp(dc, a, gen_helper_float_un_s, false, false); +} + +static bool check_pair(DisasContext *dc, int r, int p) +{ + return r + 1 + p < 32; +} + +static void load_pair(DisasContext *dc, TCGv_i64 t, int r, int p) +{ + tcg_gen_concat_i32_i64(t, cpu_R(dc, r + 1 + p), cpu_R(dc, r)); +} + +static void save_pair(DisasContext *dc, TCGv_i64 t, int r, int p) +{ + tcg_gen_extr_i64_i32(cpu_R(dc, r + 1 + p), cpu_R(dc, r), t); +} + +static bool do_dp3(DisasContext *dc, arg_dab_pair *a, + void (*fn)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) +{ + TCGv_i64 t0, t1; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->a, a->ap) || + !check_pair(dc, a->b, a->bp) || + !check_pair(dc, a->d, a->dp)) { + return false; + } + check_r0_write(dc, a->d); + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + load_pair(dc, t0, a->a, a->ap); + load_pair(dc, t1, a->b, a->bp); + fn(t0, cpu_env, t0, t1); + save_pair(dc, t0, a->d, a->dp); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool do_dp2(DisasContext *dc, arg_da_pair *a, + void (*fn)(TCGv_i64, TCGv_env, TCGv_i64)) +{ + TCGv_i64 t0; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->a, a->ap) || + !check_pair(dc, a->d, a->dp)) { + return false; + } + check_r0_write(dc, a->d); + + t0 = tcg_temp_new_i64(); + load_pair(dc, t0, a->a, a->ap); + fn(t0, cpu_env, t0); + save_pair(dc, t0, a->d, a->dp); + tcg_temp_free_i64(t0); + + gen_helper_update_fpcsr(cpu_env); return true; } +static bool do_dpcmp(DisasContext *dc, arg_ab_pair *a, + void (*fn)(TCGv, TCGv_env, TCGv_i64, TCGv_i64), + bool inv, bool swap) +{ + TCGv_i64 t0, t1; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->a, a->ap) || + !check_pair(dc, a->b, a->bp)) { + return false; + } + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + load_pair(dc, t0, a->a, a->ap); + load_pair(dc, t1, a->b, a->bp); + if (swap) { + fn(cpu_sr_f, cpu_env, t1, t0); + } else { + fn(cpu_sr_f, cpu_env, t0, t1); + } + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + + if (inv) { + tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1); + } + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool trans_lf_add_d(DisasContext *dc, arg_dab_pair *a) +{ + return do_dp3(dc, a, gen_helper_float_add_d); +} + +static bool trans_lf_sub_d(DisasContext *dc, arg_dab_pair *a) +{ + return do_dp3(dc, a, gen_helper_float_sub_d); +} + +static bool trans_lf_mul_d(DisasContext *dc, arg_dab_pair *a) +{ + return do_dp3(dc, a, gen_helper_float_mul_d); +} + +static bool trans_lf_div_d(DisasContext *dc, arg_dab_pair *a) +{ + return do_dp3(dc, a, gen_helper_float_div_d); +} + +static bool trans_lf_rem_d(DisasContext *dc, arg_dab_pair *a) +{ + return do_dp3(dc, a, gen_helper_float_rem_d); +} + +static bool trans_lf_itof_d(DisasContext *dc, arg_da_pair *a) +{ + return do_dp2(dc, a, gen_helper_itofd); +} + +static bool trans_lf_ftoi_d(DisasContext *dc, arg_da_pair *a) +{ + return do_dp2(dc, a, gen_helper_ftoid); +} + +static bool trans_lf_stod_d(DisasContext *dc, arg_lf_stod_d *a) +{ + TCGv_i64 t0; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->d, a->dp)) { + return false; + } + check_r0_write(dc, a->d); + + t0 = tcg_temp_new_i64(); + gen_helper_stod(t0, cpu_env, cpu_R(dc, a->a)); + save_pair(dc, t0, a->d, a->dp); + tcg_temp_free_i64(t0); + + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool trans_lf_dtos_d(DisasContext *dc, arg_lf_dtos_d *a) +{ + TCGv_i64 t0; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->a, a->ap)) { + return false; + } + check_r0_write(dc, a->d); + + t0 = tcg_temp_new_i64(); + load_pair(dc, t0, a->a, a->ap); + gen_helper_dtos(cpu_R(dc, a->d), cpu_env, t0); + tcg_temp_free_i64(t0); + + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool trans_lf_madd_d(DisasContext *dc, arg_dab_pair *a) +{ + TCGv_i64 t0, t1, t2; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->a, a->ap) || + !check_pair(dc, a->b, a->bp) || + !check_pair(dc, a->d, a->dp)) { + return false; + } + check_r0_write(dc, a->d); + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + load_pair(dc, t0, a->d, a->dp); + load_pair(dc, t1, a->a, a->ap); + load_pair(dc, t2, a->b, a->bp); + gen_helper_float_madd_d(t0, cpu_env, t0, t1, t2); + save_pair(dc, t0, a->d, a->dp); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool trans_lf_sfeq_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_eq_d, false, false); +} + +static bool trans_lf_sfne_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_eq_d, true, false); +} + +static bool trans_lf_sfgt_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_lt_d, false, true); +} + +static bool trans_lf_sfge_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_le_d, false, true); +} + +static bool trans_lf_sflt_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_lt_d, false, false); +} + +static bool trans_lf_sfle_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_le_d, false, false); +} + +static bool trans_lf_sfueq_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_ueq_d, false, false); +} + +static bool trans_lf_sfule_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_ule_d, false, false); +} + +static bool trans_lf_sfuge_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_ule_d, false, true); +} + +static bool trans_lf_sfult_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_ult_d, false, false); +} + +static bool trans_lf_sfugt_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_ult_d, false, true); +} + +static bool trans_lf_sfun_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_un_d, false, false); +} + static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) { DisasContext *dc = container_of(dcb, DisasContext, base); @@ -1258,6 +1596,8 @@ static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) dc->mem_idx = cpu_mmu_index(env, false); dc->tb_flags = dc->base.tb->flags; dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0; + dc->cpucfgr = env->cpucfgr; + dc->avr = env->avr; dc->jmp_pc_imm = -1; bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; @@ -1271,9 +1611,9 @@ static void openrisc_tr_tb_start(DisasContextBase *db, CPUState *cs) /* Allow the TCG optimizer to see that R0 == 0, when it's true, which is the common case. */ if (dc->tb_flags & TB_FLAGS_R0_0) { - cpu_R[0] = tcg_const_tl(0); + dc->R0 = tcg_const_tl(0); } else { - cpu_R[0] = cpu_R0; + dc->R0 = cpu_regs[0]; } } diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h index 7ffdb0a706..e499575dc8 100644 --- a/target/ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h @@ -191,6 +191,7 @@ typedef struct PowerPCCPUClass { const PPCHash64Options *hash64_opts; struct ppc_radix_page_info *radix_page_info; uint32_t lrg_decr_bits; + int n_host_threads; void (*init_proc)(CPUPPCState *env); int (*check_pow)(CPUPPCState *env); int (*handle_mmu_fault)(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx); diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 07bc9051b0..4b1a2e6178 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -630,19 +630,15 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) { CPUState *cs = env_cpu(env); int status = get_float_exception_flags(&env->fp_status); - bool inexact_happened = false; if (status & float_flag_overflow) { float_overflow_excp(env); } else if (status & float_flag_underflow) { float_underflow_excp(env); - } else if (status & float_flag_inexact) { - float_inexact_excp(env); - inexact_happened = true; } - - /* if the inexact flag was not set */ - if (inexact_happened == false) { + if (status & float_flag_inexact) { + float_inexact_excp(env); + } else { env->fpscr &= ~(1 << FPSCR_FI); /* clear the FPSCR[FI] bit */ } @@ -2887,12 +2883,40 @@ void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode, uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) { - uint64_t result; + uint64_t result, sign, exp, frac; float_status tstat = env->fp_status; set_float_exception_flags(0, &tstat); - result = (uint64_t)float64_to_float32(xb, &tstat); + sign = extract64(xb, 63, 1); + exp = extract64(xb, 52, 11); + frac = extract64(xb, 0, 52) | 0x10000000000000ULL; + + if (unlikely(exp == 0 && extract64(frac, 0, 52) != 0)) { + /* DP denormal operand. */ + /* Exponent override to DP min exp. */ + exp = 1; + /* Implicit bit override to 0. */ + frac = deposit64(frac, 53, 1, 0); + } + + if (unlikely(exp < 897 && frac != 0)) { + /* SP tiny operand. */ + if (897 - exp > 63) { + frac = 0; + } else { + /* Denormalize until exp = SP min exp. */ + frac >>= (897 - exp); + } + /* Exponent override to SP min exp - 1. */ + exp = 896; + } + + result = sign << 31; + result |= extract64(exp, 10, 1) << 30; + result |= extract64(exp, 0, 7) << 23; + result |= extract64(frac, 29, 23); + /* hardware replicates result to both words of the doubleword result. */ return (result << 32) | result; } diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 0cf3f979e2..adb8fd516f 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -163,7 +163,7 @@ struct DisasContext { int mem_idx; int access_type; /* Translation flags */ - TCGMemOp default_tcg_memop_mask; + MemOp default_tcg_memop_mask; #if defined(TARGET_PPC64) bool sf_mode; bool has_cfar; @@ -3142,7 +3142,7 @@ static void gen_isync(DisasContext *ctx) #define MEMOP_GET_SIZE(x) (1 << ((x) & MO_SIZE)) -static void gen_load_locked(DisasContext *ctx, TCGMemOp memop) +static void gen_load_locked(DisasContext *ctx, MemOp memop) { TCGv gpr = cpu_gpr[rD(ctx->opcode)]; TCGv t0 = tcg_temp_new(); @@ -3167,7 +3167,7 @@ LARX(lbarx, DEF_MEMOP(MO_UB)) LARX(lharx, DEF_MEMOP(MO_UW)) LARX(lwarx, DEF_MEMOP(MO_UL)) -static void gen_fetch_inc_conditional(DisasContext *ctx, TCGMemOp memop, +static void gen_fetch_inc_conditional(DisasContext *ctx, MemOp memop, TCGv EA, TCGCond cond, int addend) { TCGv t = tcg_temp_new(); @@ -3193,7 +3193,7 @@ static void gen_fetch_inc_conditional(DisasContext *ctx, TCGMemOp memop, tcg_temp_free(u); } -static void gen_ld_atomic(DisasContext *ctx, TCGMemOp memop) +static void gen_ld_atomic(DisasContext *ctx, MemOp memop) { uint32_t gpr_FC = FC(ctx->opcode); TCGv EA = tcg_temp_new(); @@ -3306,7 +3306,7 @@ static void gen_ldat(DisasContext *ctx) } #endif -static void gen_st_atomic(DisasContext *ctx, TCGMemOp memop) +static void gen_st_atomic(DisasContext *ctx, MemOp memop) { uint32_t gpr_FC = FC(ctx->opcode); TCGv EA = tcg_temp_new(); @@ -3389,7 +3389,7 @@ static void gen_stdat(DisasContext *ctx) } #endif -static void gen_conditional_store(DisasContext *ctx, TCGMemOp memop) +static void gen_conditional_store(DisasContext *ctx, MemOp memop) { TCGLabel *l1 = gen_new_label(); TCGLabel *l2 = gen_new_label(); diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c index 0d71c10428..2472a5217a 100644 --- a/target/ppc/translate/vmx-impl.inc.c +++ b/target/ppc/translate/vmx-impl.inc.c @@ -350,6 +350,28 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ } \ } +/* + * We use this macro if one instruction is realized with direct + * translation, and second one with helper. + */ +#define GEN_VXFORM_TRANS_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)\ +static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ +{ \ + if ((Rc(ctx->opcode) == 0) && \ + ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + trans_##name0(ctx); \ + } else if ((Rc(ctx->opcode) == 1) && \ + ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \ + gen_##name1(ctx); \ + } else { \ + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ + } \ +} + /* Adds support to provide invalid mask */ #define GEN_VXFORM_DUAL_EXT(name0, flg0, flg2_0, inval0, \ name1, flg1, flg2_1, inval1) \ @@ -431,20 +453,13 @@ GEN_VXFORM(vmrglb, 6, 4); GEN_VXFORM(vmrglh, 6, 5); GEN_VXFORM(vmrglw, 6, 6); -static void gen_vmrgew(DisasContext *ctx) +static void trans_vmrgew(DisasContext *ctx) { - TCGv_i64 tmp; - TCGv_i64 avr; - int VT, VA, VB; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - VT = rD(ctx->opcode); - VA = rA(ctx->opcode); - VB = rB(ctx->opcode); - tmp = tcg_temp_new_i64(); - avr = tcg_temp_new_i64(); + int VT = rD(ctx->opcode); + int VA = rA(ctx->opcode); + int VB = rB(ctx->opcode); + TCGv_i64 tmp = tcg_temp_new_i64(); + TCGv_i64 avr = tcg_temp_new_i64(); get_avr64(avr, VB, true); tcg_gen_shri_i64(tmp, avr, 32); @@ -462,21 +477,14 @@ static void gen_vmrgew(DisasContext *ctx) tcg_temp_free_i64(avr); } -static void gen_vmrgow(DisasContext *ctx) +static void trans_vmrgow(DisasContext *ctx) { - TCGv_i64 t0, t1; - TCGv_i64 avr; - int VT, VA, VB; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - VT = rD(ctx->opcode); - VA = rA(ctx->opcode); - VB = rB(ctx->opcode); - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - avr = tcg_temp_new_i64(); + int VT = rD(ctx->opcode); + int VA = rA(ctx->opcode); + int VB = rB(ctx->opcode); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 avr = tcg_temp_new_i64(); get_avr64(t0, VB, true); get_avr64(t1, VA, true); @@ -936,14 +944,14 @@ GEN_VXFORM_ENV(vminfp, 5, 17); GEN_VXFORM_HETRO(vextublx, 6, 24) GEN_VXFORM_HETRO(vextuhlx, 6, 25) GEN_VXFORM_HETRO(vextuwlx, 6, 26) -GEN_VXFORM_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207, +GEN_VXFORM_TRANS_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207, vextuwlx, PPC_NONE, PPC2_ISA300) GEN_VXFORM_HETRO(vextubrx, 6, 28) GEN_VXFORM_HETRO(vextuhrx, 6, 29) GEN_VXFORM_HETRO(vextuwrx, 6, 30) GEN_VXFORM_TRANS(lvsl, 6, 31) GEN_VXFORM_TRANS(lvsr, 6, 32) -GEN_VXFORM_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207, \ +GEN_VXFORM_TRANS_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207, vextuwrx, PPC_NONE, PPC2_ISA300) #define GEN_VXRFORM1(opname, name, str, opc2, opc3) \ diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c index 3922686ad6..8287e272f5 100644 --- a/target/ppc/translate/vsx-impl.inc.c +++ b/target/ppc/translate/vsx-impl.inc.c @@ -1308,7 +1308,7 @@ static void gen_##name(DisasContext *ctx) \ } \ xt = gen_vsr_ptr(xT(ctx->opcode)); \ xa = gen_vsr_ptr(xA(ctx->opcode)); \ - if (ctx->opcode & PPC_BIT(25)) { \ + if (ctx->opcode & PPC_BIT32(25)) { \ /* \ * AxT + B \ */ \ diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 4a21ed7289..0fb11c7ac6 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -8770,6 +8770,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; pcc->hash64_opts = &ppc_hash64_opts_POWER7; pcc->lrg_decr_bits = 32; + pcc->n_host_threads = 8; #endif pcc->excp_model = POWERPC_EXCP_POWER8; pcc->bus_model = PPC_FLAGS_INPUT_POWER7; @@ -8981,6 +8982,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) pcc->hash64_opts = &ppc_hash64_opts_POWER7; pcc->radix_page_info = &POWER9_radix_page_info; pcc->lrg_decr_bits = 56; + pcc->n_host_threads = 4; #endif pcc->excp_model = POWERPC_EXCP_POWER9; pcc->bus_model = PPC_FLAGS_INPUT_POWER9; @@ -10461,6 +10463,10 @@ static void ppc_cpu_reset(CPUState *s) s->exception_index = POWERPC_EXCP_NONE; env->error_code = 0; + /* tininess for underflow is detected before rounding */ + set_float_detect_tininess(float_tininess_before_rounding, + &env->fp_status); + for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { ppc_spr_t *spr = &env->spr_cb[i]; diff --git a/target/riscv/insn_trans/trans_rva.inc.c b/target/riscv/insn_trans/trans_rva.inc.c index fadd88849e..be8a9f06dd 100644 --- a/target/riscv/insn_trans/trans_rva.inc.c +++ b/target/riscv/insn_trans/trans_rva.inc.c @@ -18,7 +18,7 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ -static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, TCGMemOp mop) +static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop) { TCGv src1 = tcg_temp_new(); /* Put addr in load_res, data in load_val. */ @@ -37,7 +37,7 @@ static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, TCGMemOp mop) return true; } -static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, TCGMemOp mop) +static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop) { TCGv src1 = tcg_temp_new(); TCGv src2 = tcg_temp_new(); @@ -82,8 +82,8 @@ static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, TCGMemOp mop) } static bool gen_amo(DisasContext *ctx, arg_atomic *a, - void(*func)(TCGv, TCGv, TCGv, TCGArg, TCGMemOp), - TCGMemOp mop) + void(*func)(TCGv, TCGv, TCGv, TCGArg, MemOp), + MemOp mop) { TCGv src1 = tcg_temp_new(); TCGv src2 = tcg_temp_new(); diff --git a/target/riscv/insn_trans/trans_rvi.inc.c b/target/riscv/insn_trans/trans_rvi.inc.c index 1af795e05d..d04ca0394c 100644 --- a/target/riscv/insn_trans/trans_rvi.inc.c +++ b/target/riscv/insn_trans/trans_rvi.inc.c @@ -135,7 +135,7 @@ static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a) return gen_branch(ctx, a, TCG_COND_GEU); } -static bool gen_load(DisasContext *ctx, arg_lb *a, TCGMemOp memop) +static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop) { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -174,7 +174,7 @@ static bool trans_lhu(DisasContext *ctx, arg_lhu *a) return gen_load(ctx, a, MO_TEUW); } -static bool gen_store(DisasContext *ctx, arg_sb *a, TCGMemOp memop) +static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop) { TCGv t0 = tcg_temp_new(); TCGv dat = tcg_temp_new(); diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 91ba2e03d9..29fcce426e 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1443,9 +1443,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1, } /* Sanity check writability of the store address. */ -#ifndef CONFIG_USER_ONLY - probe_write(env, a2, 0, mem_idx, ra); -#endif + probe_write(env, a2, 1 << sc, mem_idx, ra); /* * Note that the compare-and-swap is atomic, and the store is atomic, @@ -2615,22 +2613,15 @@ uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3) void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len, uintptr_t ra) { -#ifdef CONFIG_USER_ONLY - if (!h2g_valid(addr) || !h2g_valid(addr + len - 1) || - page_check_range(addr, len, PAGE_WRITE) < 0) { - s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra); - } -#else /* test the actual access, not just any access to the page due to LAP */ while (len) { - const uint64_t pagelen = -(addr | -TARGET_PAGE_MASK); + const uint64_t pagelen = -(addr | TARGET_PAGE_MASK); const uint64_t curlen = MIN(pagelen, len); probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra); addr = wrap_address(env, addr + curlen); len -= curlen; } -#endif } void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index ac0d8b6410..2927247c82 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -152,7 +152,7 @@ static inline int vec_full_reg_offset(uint8_t reg) return offsetof(CPUS390XState, vregs[reg][0]); } -static inline int vec_reg_offset(uint8_t reg, uint8_t enr, TCGMemOp es) +static inline int vec_reg_offset(uint8_t reg, uint8_t enr, MemOp es) { /* Convert element size (es) - e.g. MO_8 - to bytes */ const uint8_t bytes = 1 << es; @@ -2262,7 +2262,7 @@ static DisasJumpType op_csst(DisasContext *s, DisasOps *o) #ifndef CONFIG_USER_ONLY static DisasJumpType op_csp(DisasContext *s, DisasOps *o) { - TCGMemOp mop = s->insn->data; + MemOp mop = s->insn->data; TCGv_i64 addr, old, cc; TCGLabel *lab = gen_new_label(); @@ -3228,7 +3228,7 @@ static DisasJumpType op_lm64(DisasContext *s, DisasOps *o) static DisasJumpType op_lpd(DisasContext *s, DisasOps *o) { TCGv_i64 a1, a2; - TCGMemOp mop = s->insn->data; + MemOp mop = s->insn->data; /* In a parallel context, stop the world and single step. */ if (tb_cflags(s->base.tb) & CF_PARALLEL) { diff --git a/target/s390x/translate_vx.inc.c b/target/s390x/translate_vx.inc.c index 0caddb3958..5ce7bfb0af 100644 --- a/target/s390x/translate_vx.inc.c +++ b/target/s390x/translate_vx.inc.c @@ -57,13 +57,13 @@ #define FPF_LONG 3 #define FPF_EXT 4 -static inline bool valid_vec_element(uint8_t enr, TCGMemOp es) +static inline bool valid_vec_element(uint8_t enr, MemOp es) { return !(enr & ~(NUM_VEC_ELEMENTS(es) - 1)); } static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr, - TCGMemOp memop) + MemOp memop) { const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE); @@ -96,7 +96,7 @@ static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr, } static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr, - TCGMemOp memop) + MemOp memop) { const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE); @@ -123,7 +123,7 @@ static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr, } static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr, - TCGMemOp memop) + MemOp memop) { const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE); @@ -146,7 +146,7 @@ static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr, } static void write_vec_element_i32(TCGv_i32 src, int reg, uint8_t enr, - TCGMemOp memop) + MemOp memop) { const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE); diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 694d7139cf..490e14dfcf 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -275,6 +275,7 @@ enum { #define TTE_VALID_BIT (1ULL << 63) #define TTE_NFO_BIT (1ULL << 60) +#define TTE_IE_BIT (1ULL << 59) #define TTE_USED_BIT (1ULL << 41) #define TTE_LOCKED_BIT (1ULL << 6) #define TTE_SIDEEFFECT_BIT (1ULL << 3) @@ -291,6 +292,7 @@ enum { #define TTE_IS_VALID(tte) ((tte) & TTE_VALID_BIT) #define TTE_IS_NFO(tte) ((tte) & TTE_NFO_BIT) +#define TTE_IS_IE(tte) ((tte) & TTE_IE_BIT) #define TTE_IS_USED(tte) ((tte) & TTE_USED_BIT) #define TTE_IS_LOCKED(tte) ((tte) & TTE_LOCKED_BIT) #define TTE_IS_SIDEEFFECT(tte) ((tte) & TTE_SIDEEFFECT_BIT) diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index cbd1e91179..77dc86ac5c 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -88,7 +88,7 @@ static const int perm_table[2][8] = { }; static int get_physical_address(CPUSPARCState *env, hwaddr *physical, - int *prot, int *access_index, + int *prot, int *access_index, MemTxAttrs *attrs, target_ulong address, int rw, int mmu_idx, target_ulong *page_size) { @@ -219,6 +219,7 @@ bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, target_ulong vaddr; target_ulong page_size; int error_code = 0, prot, access_index; + MemTxAttrs attrs = {}; /* * TODO: If we ever need tlb_vaddr_to_host for this target, @@ -229,7 +230,7 @@ bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, assert(!probe); address &= TARGET_PAGE_MASK; - error_code = get_physical_address(env, &paddr, &prot, &access_index, + error_code = get_physical_address(env, &paddr, &prot, &access_index, &attrs, address, access_type, mmu_idx, &page_size); vaddr = address; @@ -490,8 +491,8 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, return 0; } -static int get_physical_address_data(CPUSPARCState *env, - hwaddr *physical, int *prot, +static int get_physical_address_data(CPUSPARCState *env, hwaddr *physical, + int *prot, MemTxAttrs *attrs, target_ulong address, int rw, int mmu_idx) { CPUState *cs = env_cpu(env); @@ -536,6 +537,10 @@ static int get_physical_address_data(CPUSPARCState *env, if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) { int do_fault = 0; + if (TTE_IS_IE(env->dtlb[i].tte)) { + attrs->byte_swap = true; + } + /* access ok? */ /* multiple bits in SFSR.FT may be set on TT_DFAULT */ if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) { @@ -608,8 +613,8 @@ static int get_physical_address_data(CPUSPARCState *env, return 1; } -static int get_physical_address_code(CPUSPARCState *env, - hwaddr *physical, int *prot, +static int get_physical_address_code(CPUSPARCState *env, hwaddr *physical, + int *prot, MemTxAttrs *attrs, target_ulong address, int mmu_idx) { CPUState *cs = env_cpu(env); @@ -686,7 +691,7 @@ static int get_physical_address_code(CPUSPARCState *env, } static int get_physical_address(CPUSPARCState *env, hwaddr *physical, - int *prot, int *access_index, + int *prot, int *access_index, MemTxAttrs *attrs, target_ulong address, int rw, int mmu_idx, target_ulong *page_size) { @@ -716,11 +721,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical, } if (rw == 2) { - return get_physical_address_code(env, physical, prot, address, + return get_physical_address_code(env, physical, prot, attrs, address, mmu_idx); } else { - return get_physical_address_data(env, physical, prot, address, rw, - mmu_idx); + return get_physical_address_data(env, physical, prot, attrs, address, + rw, mmu_idx); } } @@ -734,10 +739,11 @@ bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, target_ulong vaddr; hwaddr paddr; target_ulong page_size; + MemTxAttrs attrs = {}; int error_code = 0, prot, access_index; address &= TARGET_PAGE_MASK; - error_code = get_physical_address(env, &paddr, &prot, &access_index, + error_code = get_physical_address(env, &paddr, &prot, &access_index, &attrs, address, access_type, mmu_idx, &page_size); if (likely(error_code == 0)) { @@ -747,7 +753,8 @@ bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, env->dmmu.mmu_primary_context, env->dmmu.mmu_secondary_context); - tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size); + tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, + page_size); return true; } if (probe) { @@ -789,7 +796,7 @@ void dump_mmu(CPUSPARCState *env) } if (TTE_IS_VALID(env->dtlb[i].tte)) { qemu_printf("[%02u] VA: %" PRIx64 ", PA: %llx" - ", %s, %s, %s, %s, ctx %" PRId64 " %s\n", + ", %s, %s, %s, %s, ie %s, ctx %" PRId64 " %s\n", i, env->dtlb[i].tag & (uint64_t)~0x1fffULL, TTE_PA(env->dtlb[i].tte), @@ -798,6 +805,8 @@ void dump_mmu(CPUSPARCState *env) TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", TTE_IS_LOCKED(env->dtlb[i].tte) ? "locked" : "unlocked", + TTE_IS_IE(env->dtlb[i].tte) ? + "yes" : "no", env->dtlb[i].tag & (uint64_t)0x1fffULL, TTE_IS_GLOBAL(env->dtlb[i].tte) ? "global" : "local"); @@ -849,9 +858,10 @@ static int cpu_sparc_get_phys_page(CPUSPARCState *env, hwaddr *phys, { target_ulong page_size; int prot, access_index; + MemTxAttrs attrs = {}; - return get_physical_address(env, phys, &prot, &access_index, addr, rw, - mmu_idx, &page_size); + return get_physical_address(env, phys, &prot, &access_index, &attrs, addr, + rw, mmu_idx, &page_size); } #if defined(TARGET_SPARC64) diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 02c16128c8..c68bf4a2e4 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -2019,7 +2019,7 @@ static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs, } static void gen_swap(DisasContext *dc, TCGv dst, TCGv src, - TCGv addr, int mmu_idx, TCGMemOp memop) + TCGv addr, int mmu_idx, MemOp memop) { gen_address_mask(dc, addr); tcg_gen_atomic_xchg_tl(dst, addr, src, mmu_idx, memop); @@ -2050,10 +2050,10 @@ typedef struct { ASIType type; int asi; int mem_idx; - TCGMemOp memop; + MemOp memop; } DisasASI; -static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop) +static DisasASI get_asi(DisasContext *dc, int insn, MemOp memop) { int asi = GET_FIELD(insn, 19, 26); ASIType type = GET_ASI_HELPER; @@ -2267,7 +2267,7 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop) } static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr, - int insn, TCGMemOp memop) + int insn, MemOp memop) { DisasASI da = get_asi(dc, insn, memop); @@ -2305,7 +2305,7 @@ static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr, } static void gen_st_asi(DisasContext *dc, TCGv src, TCGv addr, - int insn, TCGMemOp memop) + int insn, MemOp memop) { DisasASI da = get_asi(dc, insn, memop); @@ -2511,7 +2511,7 @@ static void gen_ldf_asi(DisasContext *dc, TCGv addr, case GET_ASI_BLOCK: /* Valid for lddfa on aligned registers only. */ if (size == 8 && (rd & 7) == 0) { - TCGMemOp memop; + MemOp memop; TCGv eight; int i; @@ -2625,7 +2625,7 @@ static void gen_stf_asi(DisasContext *dc, TCGv addr, case GET_ASI_BLOCK: /* Valid for stdfa on aligned registers only. */ if (size == 8 && (rd & 7) == 0) { - TCGMemOp memop; + MemOp memop; TCGv eight; int i; diff --git a/target/tilegx/translate.c b/target/tilegx/translate.c index c46a4ab151..68dd4aa2d8 100644 --- a/target/tilegx/translate.c +++ b/target/tilegx/translate.c @@ -290,7 +290,7 @@ static void gen_cmul2(TCGv tdest, TCGv tsrca, TCGv tsrcb, int sh, int rd) } static TileExcp gen_st_opcode(DisasContext *dc, unsigned dest, unsigned srca, - unsigned srcb, TCGMemOp memop, const char *name) + unsigned srcb, MemOp memop, const char *name) { if (dest) { return TILEGX_EXCP_OPCODE_UNKNOWN; @@ -305,7 +305,7 @@ static TileExcp gen_st_opcode(DisasContext *dc, unsigned dest, unsigned srca, } static TileExcp gen_st_add_opcode(DisasContext *dc, unsigned srca, unsigned srcb, - int imm, TCGMemOp memop, const char *name) + int imm, MemOp memop, const char *name) { TCGv tsrca = load_gr(dc, srca); TCGv tsrcb = load_gr(dc, srcb); @@ -496,7 +496,7 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext, { TCGv tdest, tsrca; const char *mnemonic; - TCGMemOp memop; + MemOp memop; TileExcp ret = TILEGX_EXCP_NONE; bool prefetch_nofault = false; @@ -1478,7 +1478,7 @@ static TileExcp gen_rri_opcode(DisasContext *dc, unsigned opext, TCGv tsrca = load_gr(dc, srca); bool prefetch_nofault = false; const char *mnemonic; - TCGMemOp memop; + MemOp memop; int i2, i3; TCGv t0; @@ -2106,7 +2106,7 @@ static TileExcp decode_y2(DisasContext *dc, tilegx_bundle_bits bundle) unsigned srca = get_SrcA_Y2(bundle); unsigned srcbdest = get_SrcBDest_Y2(bundle); const char *mnemonic; - TCGMemOp memop; + MemOp memop; bool prefetch_nofault = false; switch (OEY2(opc, mode)) { diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 4f10407477..c574638c9f 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -219,7 +219,7 @@ static inline void generate_trap(DisasContext *ctx, int class, int tin); /* Functions for load/save to/from memory */ static inline void gen_offset_ld(DisasContext *ctx, TCGv r1, TCGv r2, - int16_t con, TCGMemOp mop) + int16_t con, MemOp mop) { TCGv temp = tcg_temp_new(); tcg_gen_addi_tl(temp, r2, con); @@ -228,7 +228,7 @@ static inline void gen_offset_ld(DisasContext *ctx, TCGv r1, TCGv r2, } static inline void gen_offset_st(DisasContext *ctx, TCGv r1, TCGv r2, - int16_t con, TCGMemOp mop) + int16_t con, MemOp mop) { TCGv temp = tcg_temp_new(); tcg_gen_addi_tl(temp, r2, con); @@ -276,7 +276,7 @@ static void gen_offset_ld_2regs(TCGv rh, TCGv rl, TCGv base, int16_t con, } static void gen_st_preincr(DisasContext *ctx, TCGv r1, TCGv r2, int16_t off, - TCGMemOp mop) + MemOp mop) { TCGv temp = tcg_temp_new(); tcg_gen_addi_tl(temp, r2, off); @@ -286,7 +286,7 @@ static void gen_st_preincr(DisasContext *ctx, TCGv r1, TCGv r2, int16_t off, } static void gen_ld_preincr(DisasContext *ctx, TCGv r1, TCGv r2, int16_t off, - TCGMemOp mop) + MemOp mop) { TCGv temp = tcg_temp_new(); tcg_gen_addi_tl(temp, r2, off); diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 76db1741a7..c65dcf9dd7 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -53,6 +53,20 @@ static bool xtensa_cpu_has_work(CPUState *cs) #endif } +#ifdef CONFIG_USER_ONLY +static bool abi_call0; + +void xtensa_set_abi_call0(void) +{ + abi_call0 = true; +} + +bool xtensa_abi_call0(void) +{ + return abi_call0; +} +#endif + /* CPUClass::reset() */ static void xtensa_cpu_reset(CPUState *s) { @@ -70,10 +84,12 @@ static void xtensa_cpu_reset(CPUState *s) XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; env->pending_irq_level = 0; #else - env->sregs[PS] = - (xtensa_option_enabled(env->config, - XTENSA_OPTION_WINDOWED_REGISTER) ? PS_WOE : 0) | - PS_UM | (3 << PS_RING_SHIFT); + env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); + if (xtensa_option_enabled(env->config, + XTENSA_OPTION_WINDOWED_REGISTER) && + !xtensa_abi_call0()) { + env->sregs[PS] |= PS_WOE; + } #endif env->sregs[VECBASE] = env->config->vecbase; env->sregs[IBREAKENABLE] = 0; diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 0459243e6b..b363ffcf10 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -673,6 +673,9 @@ static inline MemoryRegion *xtensa_get_er_region(CPUXtensaState *env) { return env->system_er; } +#else +void xtensa_set_abi_call0(void); +bool xtensa_abi_call0(void); #endif static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env) diff --git a/tcg/README b/tcg/README index 21fcdf737f..bfa2e4ed24 100644 --- a/tcg/README +++ b/tcg/README @@ -101,7 +101,7 @@ This can be overridden using the following function modifiers: canonical locations before calling the helper. - TCG_CALL_NO_WRITE_GLOBALS means that the helper does not modify any globals. They will only be saved to their canonical location before calling helpers, - but they won't be reloaded afterwise. + but they won't be reloaded afterwards. - TCG_CALL_NO_SIDE_EFFECTS means that the call to the function is removed if the return value is not used. @@ -512,7 +512,7 @@ Both t0 and t1 may be split into little-endian ordered pairs of registers if dealing with 64-bit quantities on a 32-bit host. The memidx selects the qemu tlb index to use (e.g. user or kernel access). -The flags are the TCGMemOp bits, selecting the sign, width, and endianness +The flags are the MemOp bits, selecting the sign, width, and endianness of the memory access. For a 32-bit host, qemu_ld/st_i64 is guaranteed to only be used with a diff --git a/tcg/aarch64/tcg-target.inc.c b/tcg/aarch64/tcg-target.inc.c index 0713448bf5..3f921015d3 100644 --- a/tcg/aarch64/tcg-target.inc.c +++ b/tcg/aarch64/tcg-target.inc.c @@ -1423,7 +1423,7 @@ static inline void tcg_out_rev16(TCGContext *s, TCGReg rd, TCGReg rn) tcg_out_insn(s, 3507, REV16, TCG_TYPE_I32, rd, rn); } -static inline void tcg_out_sxt(TCGContext *s, TCGType ext, TCGMemOp s_bits, +static inline void tcg_out_sxt(TCGContext *s, TCGType ext, MemOp s_bits, TCGReg rd, TCGReg rn) { /* Using ALIASes SXTB, SXTH, SXTW, of SBFM Xd, Xn, #0, #7|15|31 */ @@ -1431,7 +1431,7 @@ static inline void tcg_out_sxt(TCGContext *s, TCGType ext, TCGMemOp s_bits, tcg_out_sbfm(s, ext, rd, rn, 0, bits); } -static inline void tcg_out_uxt(TCGContext *s, TCGMemOp s_bits, +static inline void tcg_out_uxt(TCGContext *s, MemOp s_bits, TCGReg rd, TCGReg rn) { /* Using ALIASes UXTB, UXTH of UBFM Wd, Wn, #0, #7|15 */ @@ -1580,8 +1580,8 @@ static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target) static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGMemOpIdx oi = lb->oi; - TCGMemOp opc = get_memop(oi); - TCGMemOp size = opc & MO_SIZE; + MemOp opc = get_memop(oi); + MemOp size = opc & MO_SIZE; if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) { return false; @@ -1605,8 +1605,8 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGMemOpIdx oi = lb->oi; - TCGMemOp opc = get_memop(oi); - TCGMemOp size = opc & MO_SIZE; + MemOp opc = get_memop(oi); + MemOp size = opc & MO_SIZE; if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) { return false; @@ -1649,7 +1649,7 @@ QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 8); slow path for the failure case, which will be patched later when finalizing the slow path. Generated code returns the host addend in X1, clobbers X0,X2,X3,TMP. */ -static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp opc, +static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc, tcg_insn_unit **label_ptr, int mem_index, bool is_read) { @@ -1709,11 +1709,11 @@ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp opc, #endif /* CONFIG_SOFTMMU */ -static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp memop, TCGType ext, +static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp memop, TCGType ext, TCGReg data_r, TCGReg addr_r, TCGType otype, TCGReg off_r) { - const TCGMemOp bswap = memop & MO_BSWAP; + const MemOp bswap = memop & MO_BSWAP; switch (memop & MO_SSIZE) { case MO_UB: @@ -1765,11 +1765,11 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp memop, TCGType ext, } } -static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp memop, +static void tcg_out_qemu_st_direct(TCGContext *s, MemOp memop, TCGReg data_r, TCGReg addr_r, TCGType otype, TCGReg off_r) { - const TCGMemOp bswap = memop & MO_BSWAP; + const MemOp bswap = memop & MO_BSWAP; switch (memop & MO_SIZE) { case MO_8: @@ -1804,7 +1804,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp memop, static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, TCGMemOpIdx oi, TCGType ext) { - TCGMemOp memop = get_memop(oi); + MemOp memop = get_memop(oi); const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32; #ifdef CONFIG_SOFTMMU unsigned mem_index = get_mmuidx(oi); @@ -1829,7 +1829,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, TCGMemOpIdx oi) { - TCGMemOp memop = get_memop(oi); + MemOp memop = get_memop(oi); const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32; #ifdef CONFIG_SOFTMMU unsigned mem_index = get_mmuidx(oi); diff --git a/tcg/arm/tcg-target.inc.c b/tcg/arm/tcg-target.inc.c index ece88dc2eb..94d80d79d1 100644 --- a/tcg/arm/tcg-target.inc.c +++ b/tcg/arm/tcg-target.inc.c @@ -1233,7 +1233,7 @@ QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 4); containing the addend of the tlb entry. Clobbers R0, R1, R2, TMP. */ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi, - TCGMemOp opc, int mem_index, bool is_load) + MemOp opc, int mem_index, bool is_load) { int cmp_off = (is_load ? offsetof(CPUTLBEntry, addr_read) : offsetof(CPUTLBEntry, addr_write)); @@ -1348,7 +1348,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGReg argreg, datalo, datahi; TCGMemOpIdx oi = lb->oi; - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); void *func; if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) { @@ -1412,7 +1412,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGReg argreg, datalo, datahi; TCGMemOpIdx oi = lb->oi; - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) { return false; @@ -1453,11 +1453,11 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) } #endif /* SOFTMMU */ -static inline void tcg_out_qemu_ld_index(TCGContext *s, TCGMemOp opc, +static inline void tcg_out_qemu_ld_index(TCGContext *s, MemOp opc, TCGReg datalo, TCGReg datahi, TCGReg addrlo, TCGReg addend) { - TCGMemOp bswap = opc & MO_BSWAP; + MemOp bswap = opc & MO_BSWAP; switch (opc & MO_SSIZE) { case MO_UB: @@ -1514,11 +1514,11 @@ static inline void tcg_out_qemu_ld_index(TCGContext *s, TCGMemOp opc, } } -static inline void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, +static inline void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg datalo, TCGReg datahi, TCGReg addrlo) { - TCGMemOp bswap = opc & MO_BSWAP; + MemOp bswap = opc & MO_BSWAP; switch (opc & MO_SSIZE) { case MO_UB: @@ -1577,7 +1577,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64) { TCGReg addrlo, datalo, datahi, addrhi __attribute__((unused)); TCGMemOpIdx oi; - TCGMemOp opc; + MemOp opc; #ifdef CONFIG_SOFTMMU int mem_index; TCGReg addend; @@ -1614,11 +1614,11 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64) #endif } -static inline void tcg_out_qemu_st_index(TCGContext *s, int cond, TCGMemOp opc, +static inline void tcg_out_qemu_st_index(TCGContext *s, int cond, MemOp opc, TCGReg datalo, TCGReg datahi, TCGReg addrlo, TCGReg addend) { - TCGMemOp bswap = opc & MO_BSWAP; + MemOp bswap = opc & MO_BSWAP; switch (opc & MO_SIZE) { case MO_8: @@ -1659,11 +1659,11 @@ static inline void tcg_out_qemu_st_index(TCGContext *s, int cond, TCGMemOp opc, } } -static inline void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp opc, +static inline void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg datalo, TCGReg datahi, TCGReg addrlo) { - TCGMemOp bswap = opc & MO_BSWAP; + MemOp bswap = opc & MO_BSWAP; switch (opc & MO_SIZE) { case MO_8: @@ -1708,7 +1708,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) { TCGReg addrlo, datalo, datahi, addrhi __attribute__((unused)); TCGMemOpIdx oi; - TCGMemOp opc; + MemOp opc; #ifdef CONFIG_SOFTMMU int mem_index; TCGReg addend; diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index 6ddeebf4bc..9d8ed974e0 100644 --- a/tcg/i386/tcg-target.inc.c +++ b/tcg/i386/tcg-target.inc.c @@ -1697,7 +1697,7 @@ static void * const qemu_st_helpers[16] = { First argument register is clobbered. */ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi, - int mem_index, TCGMemOp opc, + int mem_index, MemOp opc, tcg_insn_unit **label_ptr, int which) { const TCGReg r0 = TCG_REG_L0; @@ -1810,7 +1810,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, bool is_64, static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) { TCGMemOpIdx oi = l->oi; - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); TCGReg data_reg; tcg_insn_unit **label_ptr = &l->label_ptr[0]; int rexw = (l->type == TCG_TYPE_I64 ? P_REXW : 0); @@ -1895,8 +1895,8 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) { TCGMemOpIdx oi = l->oi; - TCGMemOp opc = get_memop(oi); - TCGMemOp s_bits = opc & MO_SIZE; + MemOp opc = get_memop(oi); + MemOp s_bits = opc & MO_SIZE; tcg_insn_unit **label_ptr = &l->label_ptr[0]; TCGReg retaddr; @@ -1995,10 +1995,10 @@ static inline int setup_guest_base_seg(void) static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, TCGReg base, int index, intptr_t ofs, - int seg, bool is64, TCGMemOp memop) + int seg, bool is64, MemOp memop) { - const TCGMemOp real_bswap = memop & MO_BSWAP; - TCGMemOp bswap = real_bswap; + const MemOp real_bswap = memop & MO_BSWAP; + MemOp bswap = real_bswap; int rexw = is64 * P_REXW; int movop = OPC_MOVL_GvEv; @@ -2103,7 +2103,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64) TCGReg datalo, datahi, addrlo; TCGReg addrhi __attribute__((unused)); TCGMemOpIdx oi; - TCGMemOp opc; + MemOp opc; #if defined(CONFIG_SOFTMMU) int mem_index; tcg_insn_unit *label_ptr[2]; @@ -2137,15 +2137,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64) static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, TCGReg base, int index, intptr_t ofs, - int seg, TCGMemOp memop) + int seg, MemOp memop) { /* ??? Ideally we wouldn't need a scratch register. For user-only, we could perform the bswap twice to restore the original value instead of moving to the scratch. But as it is, the L constraint means that TCG_REG_L0 is definitely free here. */ const TCGReg scratch = TCG_REG_L0; - const TCGMemOp real_bswap = memop & MO_BSWAP; - TCGMemOp bswap = real_bswap; + const MemOp real_bswap = memop & MO_BSWAP; + MemOp bswap = real_bswap; int movop = OPC_MOVL_EvGv; if (have_movbe && real_bswap) { @@ -2221,7 +2221,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) TCGReg datalo, datahi, addrlo; TCGReg addrhi __attribute__((unused)); TCGMemOpIdx oi; - TCGMemOp opc; + MemOp opc; #if defined(CONFIG_SOFTMMU) int mem_index; tcg_insn_unit *label_ptr[2]; diff --git a/tcg/mips/tcg-target.inc.c b/tcg/mips/tcg-target.inc.c index 41bff32fb4..5442167045 100644 --- a/tcg/mips/tcg-target.inc.c +++ b/tcg/mips/tcg-target.inc.c @@ -1215,7 +1215,7 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl, TCGReg addrh, TCGMemOpIdx oi, tcg_insn_unit *label_ptr[2], bool is_load) { - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); unsigned s_bits = opc & MO_SIZE; unsigned a_bits = get_alignment_bits(opc); int mem_index = get_mmuidx(oi); @@ -1313,7 +1313,7 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi, static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) { TCGMemOpIdx oi = l->oi; - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); TCGReg v0; int i; @@ -1363,8 +1363,8 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) { TCGMemOpIdx oi = l->oi; - TCGMemOp opc = get_memop(oi); - TCGMemOp s_bits = opc & MO_SIZE; + MemOp opc = get_memop(oi); + MemOp s_bits = opc & MO_SIZE; int i; /* resolve label address */ @@ -1413,7 +1413,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) #endif static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi, - TCGReg base, TCGMemOp opc, bool is_64) + TCGReg base, MemOp opc, bool is_64) { switch (opc & (MO_SSIZE | MO_BSWAP)) { case MO_UB: @@ -1521,7 +1521,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) TCGReg addr_regl, addr_regh __attribute__((unused)); TCGReg data_regl, data_regh; TCGMemOpIdx oi; - TCGMemOp opc; + MemOp opc; #if defined(CONFIG_SOFTMMU) tcg_insn_unit *label_ptr[2]; #endif @@ -1558,7 +1558,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) } static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg lo, TCGReg hi, - TCGReg base, TCGMemOp opc) + TCGReg base, MemOp opc) { /* Don't clutter the code below with checks to avoid bswapping ZERO. */ if ((lo | hi) == 0) { @@ -1624,7 +1624,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) TCGReg addr_regl, addr_regh __attribute__((unused)); TCGReg data_regl, data_regh; TCGMemOpIdx oi; - TCGMemOp opc; + MemOp opc; #if defined(CONFIG_SOFTMMU) tcg_insn_unit *label_ptr[2]; #endif diff --git a/tcg/optimize.c b/tcg/optimize.c index cee2a36a60..f7f4e873c9 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1013,7 +1013,7 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(qemu_ld): { TCGMemOpIdx oi = op->args[nb_oargs + nb_iargs]; - TCGMemOp mop = get_memop(oi); + MemOp mop = get_memop(oi); if (!(mop & MO_SIGN)) { mask = (2ULL << ((8 << (mop & MO_SIZE)) - 1)) - 1; } diff --git a/tcg/ppc/tcg-target.inc.c b/tcg/ppc/tcg-target.inc.c index 852b8940fb..815edac077 100644 --- a/tcg/ppc/tcg-target.inc.c +++ b/tcg/ppc/tcg-target.inc.c @@ -1506,7 +1506,7 @@ QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -32768); in CR7, loads the addend of the TLB into R3, and returns the register containing the guest address (zero-extended into R4). Clobbers R0 and R2. */ -static TCGReg tcg_out_tlb_read(TCGContext *s, TCGMemOp opc, +static TCGReg tcg_out_tlb_read(TCGContext *s, MemOp opc, TCGReg addrlo, TCGReg addrhi, int mem_index, bool is_read) { @@ -1633,7 +1633,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi, static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGMemOpIdx oi = lb->oi; - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); TCGReg hi, lo, arg = TCG_REG_R3; if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) { @@ -1680,8 +1680,8 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGMemOpIdx oi = lb->oi; - TCGMemOp opc = get_memop(oi); - TCGMemOp s_bits = opc & MO_SIZE; + MemOp opc = get_memop(oi); + MemOp s_bits = opc & MO_SIZE; TCGReg hi, lo, arg = TCG_REG_R3; if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) { @@ -1744,7 +1744,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) TCGReg datalo, datahi, addrlo, rbase; TCGReg addrhi __attribute__((unused)); TCGMemOpIdx oi; - TCGMemOp opc, s_bits; + MemOp opc, s_bits; #ifdef CONFIG_SOFTMMU int mem_index; tcg_insn_unit *label_ptr; @@ -1819,7 +1819,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) TCGReg datalo, datahi, addrlo, rbase; TCGReg addrhi __attribute__((unused)); TCGMemOpIdx oi; - TCGMemOp opc, s_bits; + MemOp opc, s_bits; #ifdef CONFIG_SOFTMMU int mem_index; tcg_insn_unit *label_ptr; diff --git a/tcg/riscv/tcg-target.inc.c b/tcg/riscv/tcg-target.inc.c index 3e76bf5738..7018509693 100644 --- a/tcg/riscv/tcg-target.inc.c +++ b/tcg/riscv/tcg-target.inc.c @@ -970,7 +970,7 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg addrl, TCGReg addrh, TCGMemOpIdx oi, tcg_insn_unit **label_ptr, bool is_load) { - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); unsigned s_bits = opc & MO_SIZE; unsigned a_bits = get_alignment_bits(opc); tcg_target_long compare_mask; @@ -1044,7 +1044,7 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi, static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) { TCGMemOpIdx oi = l->oi; - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); TCGReg a0 = tcg_target_call_iarg_regs[0]; TCGReg a1 = tcg_target_call_iarg_regs[1]; TCGReg a2 = tcg_target_call_iarg_regs[2]; @@ -1077,8 +1077,8 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) { TCGMemOpIdx oi = l->oi; - TCGMemOp opc = get_memop(oi); - TCGMemOp s_bits = opc & MO_SIZE; + MemOp opc = get_memop(oi); + MemOp s_bits = opc & MO_SIZE; TCGReg a0 = tcg_target_call_iarg_regs[0]; TCGReg a1 = tcg_target_call_iarg_regs[1]; TCGReg a2 = tcg_target_call_iarg_regs[2]; @@ -1121,9 +1121,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) #endif /* CONFIG_SOFTMMU */ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi, - TCGReg base, TCGMemOp opc, bool is_64) + TCGReg base, MemOp opc, bool is_64) { - const TCGMemOp bswap = opc & MO_BSWAP; + const MemOp bswap = opc & MO_BSWAP; /* We don't yet handle byteswapping, assert */ g_assert(!bswap); @@ -1172,7 +1172,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) TCGReg addr_regl, addr_regh __attribute__((unused)); TCGReg data_regl, data_regh; TCGMemOpIdx oi; - TCGMemOp opc; + MemOp opc; #if defined(CONFIG_SOFTMMU) tcg_insn_unit *label_ptr[1]; #endif @@ -1208,9 +1208,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) } static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg lo, TCGReg hi, - TCGReg base, TCGMemOp opc) + TCGReg base, MemOp opc) { - const TCGMemOp bswap = opc & MO_BSWAP; + const MemOp bswap = opc & MO_BSWAP; /* We don't yet handle byteswapping, assert */ g_assert(!bswap); @@ -1243,7 +1243,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) TCGReg addr_regl, addr_regh __attribute__((unused)); TCGReg data_regl, data_regh; TCGMemOpIdx oi; - TCGMemOp opc; + MemOp opc; #if defined(CONFIG_SOFTMMU) tcg_insn_unit *label_ptr[1]; #endif diff --git a/tcg/s390/tcg-target.inc.c b/tcg/s390/tcg-target.inc.c index fe42939d98..8aaa4cebe8 100644 --- a/tcg/s390/tcg-target.inc.c +++ b/tcg/s390/tcg-target.inc.c @@ -1430,7 +1430,7 @@ static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest) } } -static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data, +static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg data, TCGReg base, TCGReg index, int disp) { switch (opc & (MO_SSIZE | MO_BSWAP)) { @@ -1489,7 +1489,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data, } } -static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp opc, TCGReg data, +static void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg data, TCGReg base, TCGReg index, int disp) { switch (opc & (MO_SIZE | MO_BSWAP)) { @@ -1544,7 +1544,7 @@ QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 19)); /* Load and compare a TLB entry, leaving the flags set. Loads the TLB addend into R2. Returns a register with the santitized guest address. */ -static TCGReg tcg_out_tlb_read(TCGContext* s, TCGReg addr_reg, TCGMemOp opc, +static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc, int mem_index, bool is_ld) { unsigned s_bits = opc & MO_SIZE; @@ -1614,7 +1614,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) TCGReg addr_reg = lb->addrlo_reg; TCGReg data_reg = lb->datalo_reg; TCGMemOpIdx oi = lb->oi; - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL, (intptr_t)s->code_ptr, 2)) { @@ -1639,7 +1639,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) TCGReg addr_reg = lb->addrlo_reg; TCGReg data_reg = lb->datalo_reg; TCGMemOpIdx oi = lb->oi; - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL, (intptr_t)s->code_ptr, 2)) { @@ -1694,7 +1694,7 @@ static void tcg_prepare_user_ldst(TCGContext *s, TCGReg *addr_reg, static void tcg_out_qemu_ld(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, TCGMemOpIdx oi) { - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); #ifdef CONFIG_SOFTMMU unsigned mem_index = get_mmuidx(oi); tcg_insn_unit *label_ptr; @@ -1721,7 +1721,7 @@ static void tcg_out_qemu_ld(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, TCGMemOpIdx oi) { - TCGMemOp opc = get_memop(oi); + MemOp opc = get_memop(oi); #ifdef CONFIG_SOFTMMU unsigned mem_index = get_mmuidx(oi); tcg_insn_unit *label_ptr; diff --git a/tcg/sparc/tcg-target.inc.c b/tcg/sparc/tcg-target.inc.c index 10b1cea63b..d7986cda5c 100644 --- a/tcg/sparc/tcg-target.inc.c +++ b/tcg/sparc/tcg-target.inc.c @@ -1081,7 +1081,7 @@ QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 12)); is in the returned register, maybe %o0. The TLB addend is in %o1. */ static TCGReg tcg_out_tlb_load(TCGContext *s, TCGReg addr, int mem_index, - TCGMemOp opc, int which) + MemOp opc, int which) { int fast_off = TLB_MASK_TABLE_OFS(mem_index); int mask_off = fast_off + offsetof(CPUTLBDescFast, mask); @@ -1164,7 +1164,7 @@ static const int qemu_st_opc[16] = { static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, TCGMemOpIdx oi, bool is_64) { - TCGMemOp memop = get_memop(oi); + MemOp memop = get_memop(oi); #ifdef CONFIG_SOFTMMU unsigned memi = get_mmuidx(oi); TCGReg addrz, param; @@ -1246,7 +1246,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, TCGMemOpIdx oi) { - TCGMemOp memop = get_memop(oi); + MemOp memop = get_memop(oi); #ifdef CONFIG_SOFTMMU unsigned memi = get_mmuidx(oi); TCGReg addrz, param; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 587d092238..e87c327fbf 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2714,7 +2714,7 @@ void tcg_gen_lookup_and_goto_ptr(void) } } -static inline TCGMemOp tcg_canonicalize_memop(TCGMemOp op, bool is64, bool st) +static inline MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st) { /* Trigger the asserts within as early as possible. */ (void)get_alignment_bits(op); @@ -2743,7 +2743,7 @@ static inline TCGMemOp tcg_canonicalize_memop(TCGMemOp op, bool is64, bool st) } static void gen_ldst_i32(TCGOpcode opc, TCGv_i32 val, TCGv addr, - TCGMemOp memop, TCGArg idx) + MemOp memop, TCGArg idx) { TCGMemOpIdx oi = make_memop_idx(memop, idx); #if TARGET_LONG_BITS == 32 @@ -2758,7 +2758,7 @@ static void gen_ldst_i32(TCGOpcode opc, TCGv_i32 val, TCGv addr, } static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 val, TCGv addr, - TCGMemOp memop, TCGArg idx) + MemOp memop, TCGArg idx) { TCGMemOpIdx oi = make_memop_idx(memop, idx); #if TARGET_LONG_BITS == 32 @@ -2788,9 +2788,9 @@ static void tcg_gen_req_mo(TCGBar type) } } -void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop) +void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) { - TCGMemOp orig_memop; + MemOp orig_memop; tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); memop = tcg_canonicalize_memop(memop, 0, 0); @@ -2825,7 +2825,7 @@ void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop) } } -void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop) +void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) { TCGv_i32 swap = NULL; @@ -2858,9 +2858,9 @@ void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop) } } -void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop) +void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) { - TCGMemOp orig_memop; + MemOp orig_memop; if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) { tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop); @@ -2911,7 +2911,7 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop) } } -void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop) +void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) { TCGv_i64 swap = NULL; @@ -2953,7 +2953,7 @@ void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop) } } -static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, TCGMemOp opc) +static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc) { switch (opc & MO_SSIZE) { case MO_SB: @@ -2974,7 +2974,7 @@ static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, TCGMemOp opc) } } -static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, TCGMemOp opc) +static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc) { switch (opc & MO_SSIZE) { case MO_SB: @@ -3034,7 +3034,7 @@ static void * const table_cmpxchg[16] = { }; void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv, - TCGv_i32 newv, TCGArg idx, TCGMemOp memop) + TCGv_i32 newv, TCGArg idx, MemOp memop) { memop = tcg_canonicalize_memop(memop, 0, 0); @@ -3078,7 +3078,7 @@ void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv, } void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv, - TCGv_i64 newv, TCGArg idx, TCGMemOp memop) + TCGv_i64 newv, TCGArg idx, MemOp memop) { memop = tcg_canonicalize_memop(memop, 1, 0); @@ -3142,7 +3142,7 @@ void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv, } static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, - TCGArg idx, TCGMemOp memop, bool new_val, + TCGArg idx, MemOp memop, bool new_val, void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32)) { TCGv_i32 t1 = tcg_temp_new_i32(); @@ -3160,7 +3160,7 @@ static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, } static void do_atomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, - TCGArg idx, TCGMemOp memop, void * const table[]) + TCGArg idx, MemOp memop, void * const table[]) { gen_atomic_op_i32 gen; @@ -3185,7 +3185,7 @@ static void do_atomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, } static void do_nonatomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, - TCGArg idx, TCGMemOp memop, bool new_val, + TCGArg idx, MemOp memop, bool new_val, void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64)) { TCGv_i64 t1 = tcg_temp_new_i64(); @@ -3203,7 +3203,7 @@ static void do_nonatomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, } static void do_atomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val, - TCGArg idx, TCGMemOp memop, void * const table[]) + TCGArg idx, MemOp memop, void * const table[]) { memop = tcg_canonicalize_memop(memop, 1, 0); @@ -3257,7 +3257,7 @@ static void * const table_##NAME[16] = { \ WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_##NAME##q_be) \ }; \ void tcg_gen_atomic_##NAME##_i32 \ - (TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, TCGMemOp memop) \ + (TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, MemOp memop) \ { \ if (tcg_ctx->tb_cflags & CF_PARALLEL) { \ do_atomic_op_i32(ret, addr, val, idx, memop, table_##NAME); \ @@ -3267,7 +3267,7 @@ void tcg_gen_atomic_##NAME##_i32 \ } \ } \ void tcg_gen_atomic_##NAME##_i64 \ - (TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, TCGMemOp memop) \ + (TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, MemOp memop) \ { \ if (tcg_ctx->tb_cflags & CF_PARALLEL) { \ do_atomic_op_i64(ret, addr, val, idx, memop, table_##NAME); \ diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 2d4dd5cd7d..e9cf172762 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -851,10 +851,10 @@ void tcg_gen_lookup_and_goto_ptr(void); #define tcg_gen_qemu_st_tl tcg_gen_qemu_st_i64 #endif -void tcg_gen_qemu_ld_i32(TCGv_i32, TCGv, TCGArg, TCGMemOp); -void tcg_gen_qemu_st_i32(TCGv_i32, TCGv, TCGArg, TCGMemOp); -void tcg_gen_qemu_ld_i64(TCGv_i64, TCGv, TCGArg, TCGMemOp); -void tcg_gen_qemu_st_i64(TCGv_i64, TCGv, TCGArg, TCGMemOp); +void tcg_gen_qemu_ld_i32(TCGv_i32, TCGv, TCGArg, MemOp); +void tcg_gen_qemu_st_i32(TCGv_i32, TCGv, TCGArg, MemOp); +void tcg_gen_qemu_ld_i64(TCGv_i64, TCGv, TCGArg, MemOp); +void tcg_gen_qemu_st_i64(TCGv_i64, TCGv, TCGArg, MemOp); static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index) { @@ -912,46 +912,46 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) } void tcg_gen_atomic_cmpxchg_i32(TCGv_i32, TCGv, TCGv_i32, TCGv_i32, - TCGArg, TCGMemOp); + TCGArg, MemOp); void tcg_gen_atomic_cmpxchg_i64(TCGv_i64, TCGv, TCGv_i64, TCGv_i64, - TCGArg, TCGMemOp); - -void tcg_gen_atomic_xchg_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_xchg_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); - -void tcg_gen_atomic_fetch_add_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_add_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_and_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_and_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_or_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_or_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_xor_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_xor_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_smin_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_smin_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_umin_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_umin_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_smax_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_smax_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_umax_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_fetch_umax_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); - -void tcg_gen_atomic_add_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_add_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_and_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_and_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_or_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_or_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_xor_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_xor_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_smin_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_smin_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_umin_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_umin_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_smax_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_smax_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); -void tcg_gen_atomic_umax_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp); -void tcg_gen_atomic_umax_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp); + TCGArg, MemOp); + +void tcg_gen_atomic_xchg_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_xchg_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); + +void tcg_gen_atomic_fetch_add_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_fetch_add_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_fetch_and_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_fetch_and_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_fetch_or_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_fetch_or_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_fetch_xor_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_fetch_xor_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_fetch_smin_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_fetch_smin_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_fetch_umin_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_fetch_umin_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_fetch_smax_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_fetch_smax_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_fetch_umax_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_fetch_umax_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); + +void tcg_gen_atomic_add_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_add_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_and_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_and_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_or_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_or_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_xor_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_xor_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_smin_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_smin_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_umin_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_umin_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_smax_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_smax_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_umax_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); +void tcg_gen_atomic_umax_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); void tcg_gen_mov_vec(TCGv_vec, TCGv_vec); void tcg_gen_dup_i32_vec(unsigned vece, TCGv_vec, TCGv_i32); @@ -2055,7 +2055,7 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) case INDEX_op_qemu_st_i64: { TCGMemOpIdx oi = op->args[k++]; - TCGMemOp op = get_memop(oi); + MemOp op = get_memop(oi); unsigned ix = get_mmuidx(oi); if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) { @@ -26,6 +26,7 @@ #define TCG_H #include "cpu.h" +#include "exec/memop.h" #include "exec/tb-context.h" #include "qemu/bitops.h" #include "qemu/queue.h" @@ -309,103 +310,13 @@ typedef enum TCGType { #endif } TCGType; -/* Constants for qemu_ld and qemu_st for the Memory Operation field. */ -typedef enum TCGMemOp { - MO_8 = 0, - MO_16 = 1, - MO_32 = 2, - MO_64 = 3, - MO_SIZE = 3, /* Mask for the above. */ - - MO_SIGN = 4, /* Sign-extended, otherwise zero-extended. */ - - MO_BSWAP = 8, /* Host reverse endian. */ -#ifdef HOST_WORDS_BIGENDIAN - MO_LE = MO_BSWAP, - MO_BE = 0, -#else - MO_LE = 0, - MO_BE = MO_BSWAP, -#endif -#ifdef TARGET_WORDS_BIGENDIAN - MO_TE = MO_BE, -#else - MO_TE = MO_LE, -#endif - - /* - * MO_UNALN accesses are never checked for alignment. - * MO_ALIGN accesses will result in a call to the CPU's - * do_unaligned_access hook if the guest address is not aligned. - * The default depends on whether the target CPU defines - * TARGET_ALIGNED_ONLY. - * - * Some architectures (e.g. ARMv8) need the address which is aligned - * to a size more than the size of the memory access. - * Some architectures (e.g. SPARCv9) need an address which is aligned, - * but less strictly than the natural alignment. - * - * MO_ALIGN supposes the alignment size is the size of a memory access. - * - * There are three options: - * - unaligned access permitted (MO_UNALN). - * - an alignment to the size of an access (MO_ALIGN); - * - an alignment to a specified size, which may be more or less than - * the access size (MO_ALIGN_x where 'x' is a size in bytes); - */ - MO_ASHIFT = 4, - MO_AMASK = 7 << MO_ASHIFT, -#ifdef TARGET_ALIGNED_ONLY - MO_ALIGN = 0, - MO_UNALN = MO_AMASK, -#else - MO_ALIGN = MO_AMASK, - MO_UNALN = 0, -#endif - MO_ALIGN_2 = 1 << MO_ASHIFT, - MO_ALIGN_4 = 2 << MO_ASHIFT, - MO_ALIGN_8 = 3 << MO_ASHIFT, - MO_ALIGN_16 = 4 << MO_ASHIFT, - MO_ALIGN_32 = 5 << MO_ASHIFT, - MO_ALIGN_64 = 6 << MO_ASHIFT, - - /* Combinations of the above, for ease of use. */ - MO_UB = MO_8, - MO_UW = MO_16, - MO_UL = MO_32, - MO_SB = MO_SIGN | MO_8, - MO_SW = MO_SIGN | MO_16, - MO_SL = MO_SIGN | MO_32, - MO_Q = MO_64, - - MO_LEUW = MO_LE | MO_UW, - MO_LEUL = MO_LE | MO_UL, - MO_LESW = MO_LE | MO_SW, - MO_LESL = MO_LE | MO_SL, - MO_LEQ = MO_LE | MO_Q, - - MO_BEUW = MO_BE | MO_UW, - MO_BEUL = MO_BE | MO_UL, - MO_BESW = MO_BE | MO_SW, - MO_BESL = MO_BE | MO_SL, - MO_BEQ = MO_BE | MO_Q, - - MO_TEUW = MO_TE | MO_UW, - MO_TEUL = MO_TE | MO_UL, - MO_TESW = MO_TE | MO_SW, - MO_TESL = MO_TE | MO_SL, - MO_TEQ = MO_TE | MO_Q, - - MO_SSIZE = MO_SIZE | MO_SIGN, -} TCGMemOp; - /** * get_alignment_bits - * @memop: TCGMemOp value + * @memop: MemOp value * * Extract the alignment size from the memop. */ -static inline unsigned get_alignment_bits(TCGMemOp memop) +static inline unsigned get_alignment_bits(MemOp memop) { unsigned a = memop & MO_AMASK; @@ -1186,7 +1097,7 @@ static inline size_t tcg_current_code_size(TCGContext *s) return tcg_ptr_byte_diff(s->code_ptr, s->code_buf); } -/* Combine the TCGMemOp and mmu_idx parameters into a single value. */ +/* Combine the MemOp and mmu_idx parameters into a single value. */ typedef uint32_t TCGMemOpIdx; /** @@ -1196,7 +1107,7 @@ typedef uint32_t TCGMemOpIdx; * * Encode these values into a single parameter. */ -static inline TCGMemOpIdx make_memop_idx(TCGMemOp op, unsigned idx) +static inline TCGMemOpIdx make_memop_idx(MemOp op, unsigned idx) { tcg_debug_assert(idx <= 15); return (op << 4) | idx; @@ -1208,7 +1119,7 @@ static inline TCGMemOpIdx make_memop_idx(TCGMemOp op, unsigned idx) * * Extract the memory operation from the combined value. */ -static inline TCGMemOp get_memop(TCGMemOpIdx oi) +static inline MemOp get_memop(TCGMemOpIdx oi) { return oi >> 4; } diff --git a/tests/Makefile.include b/tests/Makefile.include index 49684fd4f4..b39860a8d0 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -1059,26 +1059,29 @@ BUILD_TCG_TARGET_RULES=$(patsubst %,build-tcg-tests-%, $(TARGET_DIRS)) CLEAN_TCG_TARGET_RULES=$(patsubst %,clean-tcg-tests-%, $(TARGET_DIRS)) RUN_TCG_TARGET_RULES=$(patsubst %,run-tcg-tests-%, $(TARGET_DIRS)) -ifeq ($(HAVE_USER_DOCKER),y) # Probe for the Docker Builds needed for each build $(foreach PROBE_TARGET,$(TARGET_DIRS), \ - $(eval -include $(SRC_PATH)/tests/tcg/Makefile.probe) \ - $(if $(DOCKER_PREREQ), \ - $(eval build-tcg-tests-$(PROBE_TARGET): $(DOCKER_PREREQ)))) -endif + $(eval -include $(SRC_PATH)/tests/tcg/Makefile.prereqs)) build-tcg-tests-%: - $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" \ - SKIP_DOCKER_BUILD=1 TARGET_DIR="$*/" guest-tests, \ + $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \ + -f $(SRC_PATH)/tests/tcg/Makefile.qemu \ + SRC_PATH=$(SRC_PATH) \ + V="$(V)" TARGET="$*" guest-tests, \ "BUILD", "TCG tests for $*") -run-tcg-tests-%: % build-tcg-tests-% - $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" \ - SKIP_DOCKER_BUILD=1 TARGET_DIR="$*/" run-guest-tests, \ +run-tcg-tests-%: build-tcg-tests-% %/all + $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \ + -f $(SRC_PATH)/tests/tcg/Makefile.qemu \ + SRC_PATH=$(SRC_PATH) SPEED="$(SPEED)" \ + V="$(V)" TARGET="$*" run-guest-tests, \ "RUN", "TCG tests for $*") clean-tcg-tests-%: - $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" clean-guest-tests,) + $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \ + -f $(SRC_PATH)/tests/tcg/Makefile.qemu \ + SRC_PATH=$(SRC_PATH) TARGET="$*" clean-guest-tests, \ + "CLEAN", "TCG tests for $*") .PHONY: build-tcg build-tcg: $(BUILD_TCG_TARGET_RULES) @@ -1135,7 +1138,7 @@ TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results AVOCADO_SHOW=app AVOCADO_TAGS=$(patsubst %-softmmu,-t arch:%, $(filter %-softmmu,$(TARGET_DIRS))) -ifneq ($(findstring v2,"v$(PYTHON_VERSION)"),v2) +ifneq ($(PYTHON2),y) $(TESTS_VENV_DIR): $(TESTS_VENV_REQ) $(call quiet-command, \ $(PYTHON) -m venv --system-site-packages $@, \ diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py index aee5d820ed..bd41e0443c 100644 --- a/tests/acceptance/avocado_qemu/__init__.py +++ b/tests/acceptance/avocado_qemu/__init__.py @@ -39,6 +39,9 @@ def pick_default_qemu_bin(arch=None): """ if arch is None: arch = os.uname()[4] + # qemu binary path does not match arch for powerpc, handle it + if 'ppc64le' in arch: + arch = 'ppc64' qemu_bin_relative_path = os.path.join("%s-softmmu" % arch, "qemu-system-%s" % arch) if is_readable_executable_file(qemu_bin_relative_path): diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 32159503e9..8a9a314ab4 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -76,8 +76,9 @@ class BootLinuxConsole(Test): :avocado: tags=arch:x86_64 :avocado: tags=machine:pc """ - kernel_url = ('https://download.fedoraproject.org/pub/fedora/linux/' - 'releases/29/Everything/x86_64/os/images/pxeboot/vmlinuz') + kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' + '/linux/releases/29/Everything/x86_64/os/images/pxeboot' + '/vmlinuz') kernel_hash = '23bebd2680757891cf7adedb033532163a792495' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) @@ -250,8 +251,9 @@ class BootLinuxConsole(Test): :avocado: tags=arch:aarch64 :avocado: tags=machine:virt """ - kernel_url = ('https://download.fedoraproject.org/pub/fedora/linux/' - 'releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz') + kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' + '/linux/releases/29/Everything/aarch64/os/images/pxeboot' + '/vmlinuz') kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) @@ -271,8 +273,9 @@ class BootLinuxConsole(Test): :avocado: tags=arch:arm :avocado: tags=machine:virt """ - kernel_url = ('https://download.fedoraproject.org/pub/fedora/linux/' - 'releases/29/Everything/armhfp/os/images/pxeboot/vmlinuz') + kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' + '/linux/releases/29/Everything/armhfp/os/images/pxeboot' + '/vmlinuz') kernel_hash = 'e9826d741b4fb04cadba8d4824d1ed3b7fb8b4d4' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) @@ -318,8 +321,9 @@ class BootLinuxConsole(Test): :avocado: tags=arch:s390x :avocado: tags=machine:s390_ccw_virtio """ - kernel_url = ('https://download.fedoraproject.org/pub/fedora-secondary/' - 'releases/29/Everything/s390x/os/images/kernel.img') + kernel_url = ('https://archives.fedoraproject.org/pub/archive' + '/fedora-secondary/releases/29/Everything/s390x/os/images' + '/kernel.img') kernel_hash = 'e8e8439103ef8053418ef062644ffd46a7919313' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) @@ -354,3 +358,23 @@ class BootLinuxConsole(Test): self.vm.launch() console_pattern = 'Kernel command line: %s' % kernel_command_line self.wait_for_console_pattern(console_pattern) + + def test_ppc64_pseries(self): + """ + :avocado: tags=arch:ppc64 + :avocado: tags=machine:pseries + """ + kernel_url = ('https://archives.fedoraproject.org/pub/archive' + '/fedora-secondary/releases/29/Everything/ppc64le/os' + '/ppc/ppc64/vmlinuz') + kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + self.vm.set_machine('pseries') + self.vm.set_console() + kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=hvc0' + self.vm.add_args('-kernel', kernel_path, + '-append', kernel_command_line) + self.vm.launch() + console_pattern = 'Kernel command line: %s' % kernel_command_line + self.wait_for_console_pattern(console_pattern) diff --git a/tests/acceptance/linux_initrd.py b/tests/acceptance/linux_initrd.py index 23be5a63aa..c61d9826a4 100644 --- a/tests/acceptance/linux_initrd.py +++ b/tests/acceptance/linux_initrd.py @@ -54,8 +54,9 @@ class LinuxInitrd(Test): QEMU has supported up to 4 GiB initrd for recent kernel Expect guest can reach 'Unpacking initramfs...' """ - kernel_url = ('https://mirrors.kernel.org/fedora/releases/28/' - 'Everything/x86_64/os/images/pxeboot/vmlinuz') + kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' + '/linux/releases/28/Everything/x86_64/os/images/pxeboot/' + 'vmlinuz') kernel_hash = '238e083e114c48200f80d889f7e32eeb2793e02a' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) max_size = 2 * (1024 ** 3) + 1 diff --git a/tests/acceptance/linux_ssh_mips_malta.py b/tests/acceptance/linux_ssh_mips_malta.py index aafb0c39f6..134f10cac3 100644 --- a/tests/acceptance/linux_ssh_mips_malta.py +++ b/tests/acceptance/linux_ssh_mips_malta.py @@ -162,7 +162,7 @@ class LinuxSSH(Test): self.assertIn(True, ["0dfbe8aa4c20b52e1b8bf3cb6cbdf193" in line for line in stdout]) - def do_test_mips_malta(self, endianess, kernel_path, uname_m): + def check_mips_malta(self, endianess, kernel_path, uname_m): self.boot_debian_wheezy_image_and_ssh_login(endianess, kernel_path) stdout, stderr = self.ssh_command('uname -a') @@ -184,7 +184,7 @@ class LinuxSSH(Test): kernel_hash = '592e384a4edc16dade52a6cd5c785c637bcbc9ad' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) - self.do_test_mips_malta('be', kernel_path, 'mips') + self.check_mips_malta('be', kernel_path, 'mips') @skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI') def test_mips_malta32el_kernel3_2_0(self): @@ -199,7 +199,7 @@ class LinuxSSH(Test): kernel_hash = 'a66bea5a8adaa2cb3d36a1d4e0ccdb01be8f6c2a' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) - self.do_test_mips_malta('le', kernel_path, 'mips') + self.check_mips_malta('le', kernel_path, 'mips') @skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI') def test_mips_malta64eb_kernel3_2_0(self): @@ -213,7 +213,7 @@ class LinuxSSH(Test): 'vmlinux-3.2.0-4-5kc-malta') kernel_hash = 'db6eea7de35d36c77d8c165b6bcb222e16eb91db' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) - self.do_test_mips_malta('be', kernel_path, 'mips64') + self.check_mips_malta('be', kernel_path, 'mips64') @skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI') def test_mips_malta64el_kernel3_2_0(self): @@ -227,4 +227,4 @@ class LinuxSSH(Test): 'vmlinux-3.2.0-4-5kc-malta') kernel_hash = '6a7f77245acf231415a0e8b725d91ed2f3487794' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) - self.do_test_mips_malta('le', kernel_path, 'mips64') + self.check_mips_malta('le', kernel_path, 'mips64') diff --git a/tests/acceptance/machine_m68k_nextcube.py b/tests/acceptance/machine_m68k_nextcube.py new file mode 100644 index 0000000000..e09cab9f20 --- /dev/null +++ b/tests/acceptance/machine_m68k_nextcube.py @@ -0,0 +1,121 @@ +# Functional test that boots a VM and run OCR on the framebuffer +# +# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org> +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +import os +import re +import time +import logging +import distutils.spawn + +from avocado_qemu import Test +from avocado import skipUnless +from avocado.utils import process +from avocado.utils.path import find_command, CmdNotFoundError + +PIL_AVAILABLE = True +try: + from PIL import Image +except ImportError: + PIL_AVAILABLE = False + + +def tesseract_available(expected_version): + try: + find_command('tesseract') + except CmdNotFoundError: + return False + res = process.run('tesseract --version') + try: + version = res.stdout_text.split()[1] + except IndexError: + version = res.stderr_text.split()[1] + return int(version.split('.')[0]) == expected_version + + match = re.match(r'tesseract\s(\d)', res) + if match is None: + return False + # now this is guaranteed to be a digit + return int(match.groups()[0]) == expected_version + + +class NextCubeMachine(Test): + + timeout = 15 + + def check_bootrom_framebuffer(self, screenshot_path): + rom_url = ('http://www.nextcomputers.org/NeXTfiles/Software/ROM_Files/' + '68040_Non-Turbo_Chipset/Rev_2.5_v66.BIN') + rom_hash = 'b3534796abae238a0111299fc406a9349f7fee24' + rom_path = self.fetch_asset(rom_url, asset_hash=rom_hash) + + self.vm.set_machine('next-cube') + self.vm.add_args('-bios', rom_path) + self.vm.launch() + + self.log.info('VM launched, waiting for display') + # TODO: Use avocado.utils.wait.wait_for to catch the + # 'displaysurface_create 1120x832' trace-event. + time.sleep(2) + + self.vm.command('human-monitor-command', + command_line='screendump %s' % screenshot_path) + + @skipUnless(PIL_AVAILABLE, 'Python PIL not installed') + def test_bootrom_framebuffer_size(self): + """ + :avocado: tags=arch:m68k + :avocado: tags=machine:next_cube + :avocado: tags=device:framebuffer + """ + screenshot_path = os.path.join(self.workdir, "dump.png") + self.check_bootrom_framebuffer(screenshot_path) + + width, height = Image.open(screenshot_path).size + self.assertEqual(width, 1120) + self.assertEqual(height, 832) + + @skipUnless(tesseract_available(3), 'tesseract v3 OCR tool not available') + def test_bootrom_framebuffer_ocr_with_tesseract_v3(self): + """ + :avocado: tags=arch:m68k + :avocado: tags=machine:next_cube + :avocado: tags=device:framebuffer + """ + screenshot_path = os.path.join(self.workdir, "dump.png") + self.check_bootrom_framebuffer(screenshot_path) + + console_logger = logging.getLogger('console') + text = process.run("tesseract %s stdout" % screenshot_path).stdout_text + for line in text.split('\n'): + if len(line): + console_logger.debug(line) + self.assertIn('Backplane', text) + self.assertIn('Ethernet address', text) + + # Tesseract 4 adds a new OCR engine based on LSTM neural networks. The + # new version is faster and more accurate than version 3. The drawback is + # that it is still alpha-level software. + @skipUnless(tesseract_available(4), 'tesseract v4 OCR tool not available') + def test_bootrom_framebuffer_ocr_with_tesseract_v4(self): + """ + :avocado: tags=arch:m68k + :avocado: tags=machine:next_cube + :avocado: tags=device:framebuffer + """ + screenshot_path = os.path.join(self.workdir, "dump.png") + self.check_bootrom_framebuffer(screenshot_path) + + console_logger = logging.getLogger('console') + proc = process.run("tesseract --oem 1 %s stdout" % screenshot_path) + text = proc.stdout_text + for line in text.split('\n'): + if len(line): + console_logger.debug(line) + self.assertIn('Testing the FPU, SCC', text) + self.assertIn('System test failed. Error code 51', text) + self.assertIn('Boot command', text) + self.assertIn('Next>', text) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index 6115cf6c24..a44c1ae58f 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -17,9 +17,6 @@ from avocado.utils import wait class Migration(Test): - """ - :avocado: enable - """ timeout = 10 diff --git a/tests/acceptance/pc_cpu_hotplug_props.py b/tests/acceptance/pc_cpu_hotplug_props.py new file mode 100644 index 0000000000..08b7e632c6 --- /dev/null +++ b/tests/acceptance/pc_cpu_hotplug_props.py @@ -0,0 +1,35 @@ +# +# Ensure CPU die-id can be omitted on -device +# +# Copyright (c) 2019 Red Hat Inc +# +# Author: +# Eduardo Habkost <ehabkost@redhat.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. +# + +from avocado_qemu import Test + +class OmittedCPUProps(Test): + """ + :avocado: tags=arch:x86_64 + """ + def test_no_die_id(self): + self.vm.add_args('-nodefaults', '-S') + self.vm.add_args('-smp', '1,sockets=2,cores=2,threads=2,maxcpus=8') + self.vm.add_args('-cpu', 'qemu64') + self.vm.add_args('-device', 'qemu64-x86_64-cpu,socket-id=1,core-id=0,thread-id=0') + self.vm.launch() + self.assertEquals(len(self.vm.command('query-cpus')), 2) diff --git a/tests/acceptance/vnc.py b/tests/acceptance/vnc.py index 064ceabcc1..3f40bc2be1 100644 --- a/tests/acceptance/vnc.py +++ b/tests/acceptance/vnc.py @@ -34,7 +34,7 @@ class Vnc(Test): self.assertEqual(set_password_response['error']['desc'], 'Could not set password') - def test_vnc_change_password_requires_a_password(self): + def test_change_password_requires_a_password(self): self.vm.add_args('-nodefaults', '-S', '-vnc', ':0') self.vm.launch() self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled']) @@ -48,7 +48,7 @@ class Vnc(Test): self.assertEqual(set_password_response['error']['desc'], 'Could not set password') - def test_vnc_change_password(self): + def test_change_password(self): self.vm.add_args('-nodefaults', '-S', '-vnc', ':0,password') self.vm.launch() self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled']) diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 086811e602..c8d42ceea0 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -200,7 +200,6 @@ static void ahci_shutdown(AHCIQState *ahci) { QOSState *qs = ahci->parent; - assert(!global_qtest); ahci_clean_mem(ahci); free_ahci_device(ahci->dev); g_free(ahci); diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index a356ac3489..9b3d8b0d1b 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -626,7 +626,6 @@ static void test_acpi_one(const char *params, test_data *data) test_smbios_structs(data); } - assert(!global_qtest); qtest_quit(data->qts); g_free(args); } diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c index 24852d4c7d..d3a54a0ba5 100644 --- a/tests/boot-serial-test.c +++ b/tests/boot-serial-test.c @@ -24,6 +24,17 @@ static const uint8_t kernel_mcf5208[] = { 0x60, 0xfa /* bra.s loop */ }; +static const uint8_t bios_nextcube[] = { + 0x06, 0x00, 0x00, 0x00, /* Initial SP */ + 0x01, 0x00, 0x00, 0x08, /* Initial PC */ + 0x41, 0xf9, 0x02, 0x11, 0x80, 0x00, /* lea 0x02118000,%a0 */ + 0x10, 0x3c, 0x00, 0x54, /* move.b #'T',%d0 */ + 0x11, 0x7c, 0x00, 0x05, 0x00, 0x01, /* move.b #5,1(%a0) Sel TXCTRL */ + 0x11, 0x7c, 0x00, 0x68, 0x00, 0x01, /* move.b #0x68,1(%a0) Enable TX */ + 0x11, 0x40, 0x00, 0x03, /* move.b %d0,3(%a0) Print 'T' */ + 0x60, 0xfa /* bra.s loop */ +}; + static const uint8_t kernel_pls3adsp1800[] = { 0xb0, 0x00, 0x84, 0x00, /* imm 0x8400 */ 0x30, 0x60, 0x00, 0x04, /* addik r3,r0,4 */ @@ -103,7 +114,8 @@ static testdef_t tests[] = { { "ppc64", "pseries", "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken", "Open Firmware" }, - { "ppc64", "powernv", "-cpu POWER8", "OPAL" }, + { "ppc64", "powernv8", "", "OPAL" }, + { "ppc64", "powernv9", "", "OPAL" }, { "ppc64", "sam460ex", "-device e1000", "8086 100e" }, { "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" }, { "i386", "pc", "-device sga", "SGABIOS" }, @@ -116,6 +128,7 @@ static testdef_t tests[] = { { "sparc64", "sun4u", "", "UltraSPARC" }, { "s390x", "s390-ccw-virtio", "", "device" }, { "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 }, + { "m68k", "next-cube", "", "TT", sizeof(bios_nextcube), 0, bios_nextcube }, { "microblaze", "petalogix-s3adsp1800", "", "TT", sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 }, { "microblazeel", "petalogix-ml605", "", "TT", diff --git a/tests/check-block.sh b/tests/check-block.sh index c8b6cec3f6..679aedec50 100755 --- a/tests/check-block.sh +++ b/tests/check-block.sh @@ -21,6 +21,11 @@ if grep -q "TARGET_GPROF=y" *-softmmu/config-target.mak 2>/dev/null ; then exit 0 fi +if grep -q "CFLAGS.*-fsanitize" config-host.mak 2>/dev/null ; then + echo "Sanitizers are enabled ==> Not running the qemu-iotests." + exit 0 +fi + if [ -z "$(find . -name 'qemu-system-*' -print)" ]; then echo "No qemu-system binary available ==> Not running the qemu-iotests." exit 0 diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c index 3049620854..776407e1b6 100644 --- a/tests/cpu-plug-test.c +++ b/tests/cpu-plug-test.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qapi/qmp/qdict.h" struct PlugTestData { diff --git a/tests/display-vga-test.c b/tests/display-vga-test.c index bd176dcf3a..ace3bb28e0 100644 --- a/tests/display-vga-test.c +++ b/tests/display-vga-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" static void pci_cirrus(void) { diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index cf535cbd19..50a400b573 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -6,7 +6,8 @@ DOCKER_SUFFIX := .docker DOCKER_FILES_DIR := $(SRC_PATH)/tests/docker/dockerfiles DOCKER_DEPRECATED_IMAGES := debian # we don't run tests on intermediate images (used as base by another image) -DOCKER_PARTIAL_IMAGES := debian debian8 debian9 debian8-mxe debian-ports debian-sid debian-bootstrap +DOCKER_PARTIAL_IMAGES := debian debian8 debian9 debian10 debian-sid +DEBIAN_PARTIAL_IMAGES += debian8-mxe debian-9-mxe debian-ports debian-bootstrap DOCKER_IMAGES := $(filter-out $(DOCKER_DEPRECATED_IMAGES),$(sort $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker))))) DOCKER_TARGETS := $(patsubst %,docker-image-%,$(DOCKER_IMAGES)) # Use a global constant ccache directory to speed up repetitive builds @@ -71,7 +72,8 @@ docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker $(if $(wildcard $(EXECUTABLE)), \ $(call quiet-command, \ DEB_ARCH=$(DEB_ARCH) \ - DEB_TYPE=$(DEB_TYPE) \ + DEB_TYPE=$(DEB_TYPE) \ + $(if $(DEB_URL),DEB_URL=$(DEB_URL),) \ $(DOCKER_SCRIPT) build qemu:debian-$* $< \ $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \ $(if $(NOUSER),,--add-current-user) \ @@ -86,13 +88,16 @@ docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker endif # Enforce dependencies for composite images -docker-image-debian: docker-image-debian9 docker-image-debian9-mxe: docker-image-debian9 +ifeq ($(ARCH),x86_64) docker-image-debian-amd64: docker-image-debian9 +DOCKER_PARTIAL_IMAGES += debian-amd64-cross +else +docker-image-debian-amd64-cross: docker-image-debian10 +DOCKER_PARTIAL_IMAGES += debian-amd64 +endif docker-image-debian-armel-cross: docker-image-debian9 docker-image-debian-armhf-cross: docker-image-debian9 -docker-image-debian-arm64-cross: docker-image-debian9 -docker-image-debian-buster-arm64-cross: docker-image-debian10 docker-image-debian-mips-cross: docker-image-debian9 docker-image-debian-mipsel-cross: docker-image-debian9 docker-image-debian-mips64el-cross: docker-image-debian9 @@ -101,25 +106,41 @@ docker-image-debian-s390x-cross: docker-image-debian9 docker-image-debian-win32-cross: docker-image-debian9-mxe docker-image-debian-win64-cross: docker-image-debian9-mxe -docker-image-debian-alpha-cross: docker-image-debian-sid -docker-image-debian-hppa-cross: docker-image-debian-sid -docker-image-debian-m68k-cross: docker-image-debian-sid -docker-image-debian-sh4-cross: docker-image-debian-sid -docker-image-debian-sparc64-cross: docker-image-debian-sid -docker-image-debian-mips64-cross: docker-image-debian-sid -docker-image-debian-riscv64-cross: docker-image-debian-sid -docker-image-debian-powerpc-cross: docker-image-debian-sid -docker-image-debian-ppc64-cross: docker-image-debian-sid +# For non-x86 hosts not all cross-compilers have been packaged +ifneq ($(ARCH),x86_64) +DOCKER_PARTIAL_IMAGES += debian-mips-cross debian-mipsel-cross debian-mips64el-cross +DOCKER_PARTIAL_IMAGES += debian-ppc64el-cross +DOCKER_PARTIAL_IMAGES += debian-s390x-cross +DOCKER_PARTIAL_IMAGES += debian-win32-cross debian-win64-cross +DOCKER_PARTIAL_IMAGES += fedora travis +endif + +docker-image-debian-alpha-cross: docker-image-debian10 +docker-image-debian-arm64-cross: docker-image-debian10 +docker-image-debian-hppa-cross: docker-image-debian10 +docker-image-debian-m68k-cross: docker-image-debian10 +docker-image-debian-mips64-cross: docker-image-debian10 +docker-image-debian-powerpc-cross: docker-image-debian10 +docker-image-debian-ppc64-cross: docker-image-debian10 +docker-image-debian-riscv64-cross: docker-image-debian10 +docker-image-debian-sh4-cross: docker-image-debian10 +docker-image-debian-sparc64-cross: docker-image-debian10 + docker-image-travis: NOUSER=1 # Specialist build images, sometimes very limited tools docker-image-tricore-cross: docker-image-debian9 # These images may be good enough for building tests but not for test builds -DOCKER_PARTIAL_IMAGES += debian-alpha-cross debian-hppa-cross debian-m68k-cross debian-sh4-cross -DOCKER_PARTIAL_IMAGES += debian-sparc64-cross debian-mips64-cross debian-riscv64-cross -DOCKER_PARTIAL_IMAGES += debian-tricore-cross debian-powerpc-cross fedora-i386-cross -DOCKER_PARTIAL_IMAGES += fedora-cris-cross +DOCKER_PARTIAL_IMAGES += debian-alpha-cross +DOCKER_PARTIAL_IMAGES += debian-hppa-cross +DOCKER_PARTIAL_IMAGES += debian-m68k-cross debian-mips64-cross +DOCKER_PARTIAL_IMAGES += debian-powerpc-cross debian-ppc64-cross +DOCKER_PARTIAL_IMAGES += debian-riscv64-cross +DOCKER_PARTIAL_IMAGES += debian-sh4-cross debian-sparc64-cross +DOCKER_PARTIAL_IMAGES += debian-tricore-cross +DOCKER_PARTIAL_IMAGES += debian-xtensa-cross +DOCKER_PARTIAL_IMAGES += fedora-i386-cross fedora-cris-cross # Rules for building linux-user powered images # @@ -131,6 +152,7 @@ DOCKER_PARTIAL_IMAGES += fedora-cris-cross # broken so we need a qemu-linux-user for this target docker-binfmt-image-debian-powerpc-user: DEB_ARCH = powerpc docker-binfmt-image-debian-powerpc-user: DEB_TYPE = jessie +docker-binfmt-image-debian-powerpc-user: DEB_URL = http://snapshot.debian.org/archive/debian/20180615T211437Z docker-binfmt-image-debian-powerpc-user: EXECUTABLE = ${BUILD_DIR}/ppc-linux-user/qemu-ppc docker-image-debian-powerpc-user-cross: docker-binfmt-image-debian-powerpc-user DOCKER_USER_IMAGES += debian-powerpc-user diff --git a/tests/docker/common.rc b/tests/docker/common.rc index 4011561587..512202b0a1 100755 --- a/tests/docker/common.rc +++ b/tests/docker/common.rc @@ -11,6 +11,10 @@ # or (at your option) any later version. See the COPYING file in # the top-level directory. +# This might be set by ENV of a docker container... it is always +# overriden by TARGET_LIST if the user sets it. +DEF_TARGET_LIST=${DEF_TARGET_LIST:-"x86_64-softmmu,aarch64-softmmu"} + requires() { for c in $@; do diff --git a/tests/docker/docker.py b/tests/docker/docker.py index ac5baab4ca..29613afd48 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Docker controlling module # @@ -11,7 +11,6 @@ # or (at your option) any later version. See the COPYING file in # the top-level directory. -from __future__ import print_function import os import sys import subprocess @@ -25,10 +24,7 @@ import tempfile import re import signal from tarfile import TarFile, TarInfo -try: - from StringIO import StringIO -except ImportError: - from io import StringIO +from io import StringIO from shutil import copy, rmtree from pwd import getpwuid from datetime import datetime, timedelta @@ -62,11 +58,13 @@ USE_ENGINE = EngineEnum.AUTO def _text_checksum(text): """Calculate a digest string unique to the text content""" - return hashlib.sha1(text).hexdigest() + return hashlib.sha1(text.encode('utf-8')).hexdigest() +def _read_dockerfile(path): + return open(path, 'rt', encoding='utf-8').read() def _file_checksum(filename): - return _text_checksum(open(filename, 'rb').read()) + return _text_checksum(_read_dockerfile(filename)) def _guess_engine_command(): @@ -113,7 +111,7 @@ def _get_so_libs(executable): libs = [] ldd_re = re.compile(r"(/.*/)(\S*)") try: - ldd_output = subprocess.check_output(["ldd", executable]) + ldd_output = subprocess.check_output(["ldd", executable]).decode('utf-8') for line in ldd_output.split("\n"): search = ldd_re.search(line) if search and len(search.groups()) == 2: @@ -192,7 +190,7 @@ def _read_qemu_dockerfile(img_name): df = os.path.join(os.path.dirname(__file__), "dockerfiles", img_name + ".docker") - return open(df, "r").read() + return _read_dockerfile(df) def _dockerfile_preprocess(df): @@ -260,9 +258,16 @@ class Docker(object): return self._do_kill_instances(True) def _output(self, cmd, **kwargs): - return subprocess.check_output(self._command + cmd, - stderr=subprocess.STDOUT, - **kwargs) + if sys.version_info[1] >= 6: + return subprocess.check_output(self._command + cmd, + stderr=subprocess.STDOUT, + encoding='utf-8', + **kwargs) + else: + return subprocess.check_output(self._command + cmd, + stderr=subprocess.STDOUT, + **kwargs).decode('utf-8') + def inspect_tag(self, tag): try: @@ -283,7 +288,9 @@ class Docker(object): if argv is None: argv = [] - tmp_df = tempfile.NamedTemporaryFile(dir=docker_dir, suffix=".docker") + tmp_df = tempfile.NamedTemporaryFile(mode="w+t", + encoding='utf-8', + dir=docker_dir, suffix=".docker") tmp_df.write(dockerfile) if user: @@ -317,10 +324,18 @@ class Docker(object): return False return checksum == _text_checksum(_dockerfile_preprocess(dockerfile)) - def run(self, cmd, keep, quiet): + def run(self, cmd, keep, quiet, as_user=False): label = uuid.uuid1().hex if not keep: self._instances.append(label) + + if as_user: + uid = os.getuid() + cmd = [ "-u", str(uid) ] + cmd + # podman requires a bit more fiddling + if self._command[0] == "podman": + argv.insert(0, '--userns=keep-id') + ret = self._do_check(["run", "--label", "com.qemu.instance.uuid=" + label] + cmd, quiet=quiet) @@ -363,15 +378,8 @@ class RunCommand(SubCommand): help="Run container using the current user's uid") def run(self, args, argv): - if args.run_as_current_user: - uid = os.getuid() - argv = [ "-u", str(uid) ] + argv - docker = Docker() - if docker._command[0] == "podman": - argv = [ "--uidmap", "%d:0:1" % uid, - "--uidmap", "0:1:%d" % uid, - "--uidmap", "%d:%d:64536" % (uid + 1, uid + 1)] + argv - return Docker().run(argv, args.keep, quiet=args.quiet) + return Docker().run(argv, args.keep, quiet=args.quiet, + as_user=args.run_as_current_user) class BuildCommand(SubCommand): @@ -396,7 +404,7 @@ class BuildCommand(SubCommand): help="Dockerfile name") def run(self, args, argv): - dockerfile = open(args.dockerfile, "rb").read() + dockerfile = _read_dockerfile(args.dockerfile) tag = args.tag dkr = Docker() @@ -442,7 +450,7 @@ class BuildCommand(SubCommand): cksum += [(filename, _file_checksum(filename))] argv += ["--build-arg=" + k.lower() + "=" + v - for k, v in os.environ.iteritems() + for k, v in os.environ.items() if k.lower() in FILTERED_ENV_NAMES] dkr.build_image(tag, docker_dir, dockerfile, quiet=args.quiet, user=args.user, argv=argv, @@ -535,9 +543,9 @@ class ProbeCommand(SubCommand): try: docker = Docker() if docker._command[0] == "docker": - print("yes") + print("docker") elif docker._command[0] == "sudo": - print("sudo") + print("sudo docker") elif docker._command[0] == "podman": print("podman") except Exception: @@ -555,8 +563,6 @@ class CcCommand(SubCommand): help="The docker image in which to run cc") parser.add_argument("--cc", default="cc", help="The compiler executable to call") - parser.add_argument("--user", - help="The user-id to run under") parser.add_argument("--source-path", "-s", nargs="*", dest="paths", help="""Extra paths to (ro) mount into container for reading sources""") @@ -570,11 +576,10 @@ class CcCommand(SubCommand): if args.paths: for p in args.paths: cmd += ["-v", "%s:%s:ro,z" % (p, p)] - if args.user: - cmd += ["-u", args.user] cmd += [args.image, args.cc] cmd += argv - return Docker().command("run", cmd, args.quiet) + return Docker().run(cmd, False, quiet=args.quiet, + as_user=True) class CheckCommand(SubCommand): @@ -611,7 +616,7 @@ class CheckCommand(SubCommand): print("Need a dockerfile for tag:%s" % (tag)) return 1 - dockerfile = open(args.dockerfile, "rb").read() + dockerfile = _read_dockerfile(args.dockerfile) if dkr.image_matches_dockerfile(tag, dockerfile): if not args.quiet: @@ -650,7 +655,8 @@ def main(): cmd.args(subp) subp.set_defaults(cmdobj=cmd) args, argv = parser.parse_known_args() - USE_ENGINE = args.engine + if args.engine: + USE_ENGINE = args.engine return args.cmdobj.run(args, argv) diff --git a/tests/docker/dockerfiles/debian-alpha-cross.docker b/tests/docker/dockerfiles/debian-alpha-cross.docker index 23444342f0..74bcabfdb1 100644 --- a/tests/docker/dockerfiles/debian-alpha-cross.docker +++ b/tests/docker/dockerfiles/debian-alpha-cross.docker @@ -1,13 +1,12 @@ # # Docker cross-compiler target # -# This docker target builds on the debian sid base image which -# contains cross compilers for Debian "ports" targets. +# This docker target builds on the debian Buster base image. # -FROM qemu:debian-sid +FROM qemu:debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt install -y --no-install-recommends \ gcc-alpha-linux-gnu \ - libc6.1-dev-alpha-cross || { echo "Failed to build - see debian-sid.docker notes"; exit 1; } + libc6.1-dev-alpha-cross diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker new file mode 100644 index 0000000000..5d89041925 --- /dev/null +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -0,0 +1,22 @@ +# +# Docker x86_64 cross target +# +# This docker target is used on non-x86_64 machines which need the +# x86_64 cross compilers installed. +# +FROM qemu:debian10 +MAINTAINER Alex Bennée <alex.bennee@linaro.org> + +# Add the foreign architecture we want and install dependencies +RUN dpkg --add-architecture amd64 +RUN apt update && \ + DEBIAN_FRONTEND=noninteractive eatmydata \ + apt install -y --no-install-recommends \ + crossbuild-essential-amd64 +RUN apt update && \ + DEBIAN_FRONTEND=noninteractive eatmydata \ + apt build-dep -yy -a amd64 --arch-only qemu + +# Specify the cross prefix for this image (see tests/docker/common.rc) +ENV QEMU_CONFIGURE_OPTS --cross-prefix=x86_64-linux-gnu- +ENV DEF_TARGET_LIST x86_64-softmmu,x86_64-linux-user,i386-softmmu,i386-linux-user diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 7c2cc93daf..09ca0a1ba7 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -1,9 +1,9 @@ # # Docker arm64 cross-compiler target # -# This docker target builds on the debian Stretch base image. +# This docker target builds on the debian Buster base image. # -FROM qemu:debian9 +FROM qemu:debian10 # Add the foreign architecture we want and install dependencies RUN dpkg --add-architecture arm64 @@ -13,10 +13,11 @@ RUN apt update && \ crossbuild-essential-arm64 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a arm64 qemu + apt build-dep -yy -a arm64 --arch-only qemu # Specify the cross prefix for this image (see tests/docker/common.rc) ENV QEMU_CONFIGURE_OPTS --cross-prefix=aarch64-linux-gnu- +ENV DEF_TARGET_LIST aarch64-softmmu,aarch64-linux-user RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker index d866fe5d75..15378f8ea2 100644 --- a/tests/docker/dockerfiles/debian-armel-cross.docker +++ b/tests/docker/dockerfiles/debian-armel-cross.docker @@ -11,10 +11,11 @@ RUN dpkg --add-architecture armel && \ apt update && \ apt install -yy crossbuild-essential-armel && \ DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a armel qemu + apt build-dep -yy -a armel --arch-only qemu # Specify the cross prefix for this image (see tests/docker/common.rc) ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabi- +ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user,armeb-linux-user RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index 2b8627673c..4a20af6fe1 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -13,10 +13,11 @@ RUN apt update && \ crossbuild-essential-armhf RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a armhf qemu + apt build-dep -yy -a armhf --arch-only qemu # Specify the cross prefix for this image (see tests/docker/common.rc) ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabihf- +ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user,armeb-linux-user RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-buster-arm64-cross.docker b/tests/docker/dockerfiles/debian-buster-arm64-cross.docker deleted file mode 100644 index 52787edcc2..0000000000 --- a/tests/docker/dockerfiles/debian-buster-arm64-cross.docker +++ /dev/null @@ -1,16 +0,0 @@ -# -# Docker arm64 cross-compiler target -# -# This docker target builds on the Debian's Buster base image. There -# are no QEMU pre-requistes so this image can only be used to build -# test cases. -# -FROM qemu:debian10 - -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture arm64 -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt-get install -y --no-install-recommends \ - crossbuild-essential-arm64 diff --git a/tests/docker/dockerfiles/debian-hppa-cross.docker b/tests/docker/dockerfiles/debian-hppa-cross.docker index ee6d9a24ce..5c68b2d330 100644 --- a/tests/docker/dockerfiles/debian-hppa-cross.docker +++ b/tests/docker/dockerfiles/debian-hppa-cross.docker @@ -1,10 +1,9 @@ # # Docker cross-compiler target # -# This docker target builds on the debian sid base image which -# contains cross compilers for Debian "ports" targets. +# This docker target builds on the debian Buster base image. # -FROM qemu:debian-sid +FROM qemu:debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-m68k-cross.docker b/tests/docker/dockerfiles/debian-m68k-cross.docker index 4311c9cf86..25edc80e9a 100644 --- a/tests/docker/dockerfiles/debian-m68k-cross.docker +++ b/tests/docker/dockerfiles/debian-m68k-cross.docker @@ -1,10 +1,9 @@ # # Docker cross-compiler target # -# This docker target builds on the debian sid base image which -# contains cross compilers for Debian "ports" targets. +# This docker target builds on the debian Buster base image. # -FROM qemu:debian-sid +FROM qemu:debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-mips-cross.docker b/tests/docker/dockerfiles/debian-mips-cross.docker index 3c4d6f9ec1..08a8e1c29c 100644 --- a/tests/docker/dockerfiles/debian-mips-cross.docker +++ b/tests/docker/dockerfiles/debian-mips-cross.docker @@ -1,9 +1,9 @@ # # Docker mips cross-compiler target # -# This docker target builds on the debian Stretch base image. +# This docker target builds on the debian Buster base image. # -FROM qemu:debian9 +FROM qemu:debian10 MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org> @@ -16,10 +16,11 @@ RUN apt update && \ RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a mips qemu + apt build-dep -yy -a mips --arch-only qemu # Specify the cross prefix for this image (see tests/docker/common.rc) ENV QEMU_CONFIGURE_OPTS --cross-prefix=mips-linux-gnu- +ENV DEF_TARGET_LIST mips-softmmu,mipsel-linux-user # Install extra libraries to increase code coverage RUN apt update && \ diff --git a/tests/docker/dockerfiles/debian-mips64-cross.docker b/tests/docker/dockerfiles/debian-mips64-cross.docker index bf0073a466..1a79505d69 100644 --- a/tests/docker/dockerfiles/debian-mips64-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64-cross.docker @@ -1,10 +1,9 @@ # # Docker cross-compiler target # -# This docker target builds on the debian sid base image which -# contains cross compilers for Debian "ports" targets. +# This docker target builds on the debian Buster base image. # -FROM qemu:debian-sid +FROM qemu:debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker index 34b0b82895..2fca112405 100644 --- a/tests/docker/dockerfiles/debian-mips64el-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker @@ -17,10 +17,11 @@ RUN dpkg --add-architecture mips64el && \ RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a mips64el qemu + apt build-dep -yy -a mips64el --arch-only qemu # Specify the cross prefix for this image (see tests/docker/common.rc) ENV QEMU_CONFIGURE_OPTS --cross-prefix=mips64el-linux-gnuabi64- +ENV DEF_TARGET_LIST mips64el-softmmu,mips64el-linux-user # Install extra libraries to increase code coverage RUN apt update && \ diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker index 88accad269..4abf7832ac 100644 --- a/tests/docker/dockerfiles/debian-mipsel-cross.docker +++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker @@ -16,7 +16,7 @@ RUN apt update && \ RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a mipsel qemu + apt build-dep -yy -a mipsel --arch-only qemu # Specify the cross prefix for this image (see tests/docker/common.rc) ENV QEMU_CONFIGURE_OPTS --cross-prefix=mipsel-linux-gnu- diff --git a/tests/docker/dockerfiles/debian-powerpc-cross.docker b/tests/docker/dockerfiles/debian-powerpc-cross.docker index 5d08fad7cd..89dd4fbf87 100644 --- a/tests/docker/dockerfiles/debian-powerpc-cross.docker +++ b/tests/docker/dockerfiles/debian-powerpc-cross.docker @@ -1,14 +1,12 @@ # # Docker powerpc cross-compiler target # -# This docker target builds on the debian sid base image which -# contains cross compilers for Debian "ports" targets. The original -# Jessie based no longer builds. +# This docker target builds on the debian Buster base image. # -FROM qemu:debian-sid +FROM qemu:debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt install -y --no-install-recommends \ gcc-powerpc-linux-gnu \ - libc6-dev-powerpc-cross || { echo "Failed to build - see debian-sid.docker notes"; exit 1; } + libc6-dev-powerpc-cross diff --git a/tests/docker/dockerfiles/debian-powerpc-user-cross.docker b/tests/docker/dockerfiles/debian-powerpc-user-cross.docker index 6938a845ee..83749b0abb 100644 --- a/tests/docker/dockerfiles/debian-powerpc-user-cross.docker +++ b/tests/docker/dockerfiles/debian-powerpc-user-cross.docker @@ -8,8 +8,14 @@ # debootstrapped qemu:debian-powerpc-user but doesn't need any extra # magic once it is setup. # +# It can be used to build old versions of QEMU, current versions need +# newer dependencies than Jessie provides. +# FROM qemu:debian-powerpc-user RUN echo man-db man-db/auto-update boolean false | debconf-set-selections RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get build-dep -yy qemu + DEBIAN_FRONTEND=noninteractive apt-get build-dep -yy qemu + +ENV QEMU_CONFIGURE_OPTS --disable-werror +ENV DEF_TARGET_LIST powerpc-softmmu,arm-linux-user,aarch64-linux-user diff --git a/tests/docker/dockerfiles/debian-ppc64-cross.docker b/tests/docker/dockerfiles/debian-ppc64-cross.docker index e5757fe46e..4bf88ab02d 100644 --- a/tests/docker/dockerfiles/debian-ppc64-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64-cross.docker @@ -1,12 +1,11 @@ # # Docker ppc64 cross-compiler target # -# This docker target builds on the debian sid base image which -# contains cross compilers for Debian "ports" targets. -FROM qemu:debian-sid +# This docker target builds on the debian Buster base image. +FROM qemu:debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt install -y --no-install-recommends \ gcc-powerpc64-linux-gnu \ - libc6-dev-ppc64-cross || { echo "Failed to build - see debian-sid.docker notes"; exit 1; } + libc6-dev-ppc64-cross diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index fc056d7bc3..9973df9ff7 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -12,10 +12,11 @@ RUN dpkg --add-architecture ppc64el && \ RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a ppc64el qemu + apt build-dep -yy -a ppc64el --arch-only qemu # Specify the cross prefix for this image (see tests/docker/common.rc) ENV QEMU_CONFIGURE_OPTS --cross-prefix=powerpc64le-linux-gnu- +ENV DEF_TARGET_LIST ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user # Install extra libraries to increase code coverage RUN apt update && \ diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker index 221697f9d1..5e2d6ddb60 100644 --- a/tests/docker/dockerfiles/debian-riscv64-cross.docker +++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker @@ -1,10 +1,9 @@ # # Docker cross-compiler target # -# This docker target builds on the debian sid base image which -# contains cross compilers for Debian "ports" targets. +# This docker target builds on the debian Buster base image. # -FROM qemu:debian-sid +FROM qemu:debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index 6732f9ec78..eb73c98855 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -17,10 +17,11 @@ RUN apt update && \ RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a s390x qemu + apt build-dep -yy -a s390x --arch-only qemu # Specify the cross prefix for this image (see tests/docker/common.rc) ENV QEMU_CONFIGURE_OPTS --cross-prefix=s390x-linux-gnu- +ENV DEF_TARGET_LIST s390x-softmmu,s390x-linux-user # Install extra libraries to increase code coverage RUN apt update && \ diff --git a/tests/docker/dockerfiles/debian-sh4-cross.docker b/tests/docker/dockerfiles/debian-sh4-cross.docker index 29983b2d75..9d7663764e 100644 --- a/tests/docker/dockerfiles/debian-sh4-cross.docker +++ b/tests/docker/dockerfiles/debian-sh4-cross.docker @@ -1,10 +1,9 @@ # # Docker cross-compiler target # -# This docker target builds on the debian sid base image which -# contains cross compilers for Debian "ports" targets. +# This docker target builds on the debian Buster base image. # -FROM qemu:debian-sid +FROM qemu:debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/debian-sid.docker b/tests/docker/dockerfiles/debian-sid.docker index 513459ca7f..2a1bcc33b2 100644 --- a/tests/docker/dockerfiles/debian-sid.docker +++ b/tests/docker/dockerfiles/debian-sid.docker @@ -1,25 +1,19 @@ # # Debian Sid Base # -# A number of our guests exist as ports only. We can either use the -# ports repo or get everything from Sid. However Sid is a rolling -# distro which may be broken at any particular time. If you are -# unlucky and try and build your images while gcc is in the process of -# being uploaded this can fail. Your only recourse is to try again in -# a few hours when the repos have re-synced. Once built however you -# won't be affected by repo changes unless the docker recipies are -# updated and trigger a re-build. +# Currently we can build all our guests with cross-compilers in the +# latest Debian release (Buster). However new compilers will first +# arrive in Sid. However Sid is a rolling distro which may be broken +# at any particular time. To try and mitigate this we use Debian's +# snapshot archive which provides a "stable" view of what state Sid +# was in. # # This must be earlier than the snapshot date we are aiming for -FROM debian:sid-20181011-slim +FROM debian:sid-20190812-slim -# Use a snapshot known to work (see http://snapshot.debian.org/#Usage) -ENV DEBIAN_SNAPSHOT_DATE "20181030" -RUN sed -i "s%^deb \(https\?://\)deb.debian.org/debian/\? \(.*\)%deb [check-valid-until=no] \1snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT_DATE} \2%" /etc/apt/sources.list - -# Use a snapshot known to work (see http://snapshot.debian.org/#Usage) -ENV DEBIAN_SNAPSHOT_DATE "20181030" + # Use a snapshot known to work (see http://snapshot.debian.org/#Usage) +ENV DEBIAN_SNAPSHOT_DATE "20190820" RUN sed -i "s%^deb \(https\?://\)deb.debian.org/debian/\? \(.*\)%deb [check-valid-until=no] \1snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT_DATE} \2%" /etc/apt/sources.list # Duplicate deb line as deb-src diff --git a/tests/docker/dockerfiles/debian-sparc64-cross.docker b/tests/docker/dockerfiles/debian-sparc64-cross.docker index 7a2c2ab19c..31fd34f120 100644 --- a/tests/docker/dockerfiles/debian-sparc64-cross.docker +++ b/tests/docker/dockerfiles/debian-sparc64-cross.docker @@ -1,10 +1,9 @@ # # Docker cross-compiler target # -# This docker target builds on the debian sid base image which -# contains cross compilers for Debian "ports" targets. +# This docker target builds on the debian Buster base image. # -FROM qemu:debian-sid +FROM qemu:debian10 RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker index 44bbf0f77a..883f9bcf31 100644 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ b/tests/docker/dockerfiles/ubuntu1804.docker @@ -56,3 +56,6 @@ RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES RUN dpkg -l $PACKAGES | sort > /packages.txt ENV FEATURES clang pyyaml sdl2 + +# https://bugs.launchpad.net/qemu/+bug/1838763 +ENV QEMU_CONFIGURE_OPTS --disable-libssh diff --git a/tests/docker/run b/tests/docker/run index 1014871fec..8edc7026ee 100755 --- a/tests/docker/run +++ b/tests/docker/run @@ -62,7 +62,7 @@ echo "* Prepared to run command:" echo " $CMD" echo "* Hit Ctrl-D to continue, or type 'exit 1' to abort" echo -$SHELL --noprofile --norc +env bash --noprofile --norc if "$CMD"; then exit 0 @@ -72,7 +72,7 @@ elif test -n "$DEBUG"; then echo "* Hit Ctrl-D to exit" echo # Force error after shell exits - $SHELL --noprofile --norc && exit 1 + env bash --noprofile --norc && exit 1 else exit 1 fi diff --git a/tests/docker/test-build b/tests/docker/test-build index 22766cfacc..2b2a7832f1 100755 --- a/tests/docker/test-build +++ b/tests/docker/test-build @@ -15,7 +15,6 @@ cd "$BUILD_DIR" -DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu" TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ build_qemu install_qemu diff --git a/tests/docker/test-mingw b/tests/docker/test-mingw index fdb1c2c879..c30eb654eb 100755 --- a/tests/docker/test-mingw +++ b/tests/docker/test-mingw @@ -16,7 +16,6 @@ requires mingw dtc cd "$BUILD_DIR" -DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu" for prefix in x86_64-w64-mingw32- i686-w64-mingw32-; do TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ diff --git a/tests/docker/test-quick b/tests/docker/test-quick index eee59c55fb..feee44b247 100755 --- a/tests/docker/test-quick +++ b/tests/docker/test-quick @@ -15,7 +15,6 @@ cd "$BUILD_DIR" -DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu" TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ build_qemu check_qemu diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c index 93628c588d..1a232a663a 100644 --- a/tests/e1000e-test.c +++ b/tests/e1000e-test.c @@ -26,7 +26,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qemu-common.h" #include "libqos/pci-pc.h" #include "qemu/sockets.h" diff --git a/tests/fdc-test.c b/tests/fdc-test.c index 31cd3295c1..26b69f7c5c 100644 --- a/tests/fdc-test.c +++ b/tests/fdc-test.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qapi/qmp/qdict.h" #include "qemu-common.h" diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c index 69205b58a8..1f57d9684b 100644 --- a/tests/i440fx-test.c +++ b/tests/i440fx-test.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "libqos/pci.h" #include "libqos/pci-pc.h" #include "hw/pci/pci_regs.h" diff --git a/tests/i82801b11-test.c b/tests/i82801b11-test.c index a6e31594c9..4345da338b 100644 --- a/tests/i82801b11-test.c +++ b/tests/i82801b11-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/tests/intel-hda-test.c b/tests/intel-hda-test.c index b782b2e944..fc25ccc33c 100644 --- a/tests/intel-hda-test.c +++ b/tests/intel-hda-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #define HDA_ID "hda0" #define CODEC_DEVICES " -device hda-output,bus=" HDA_ID ".0" \ diff --git a/tests/ioh3420-test.c b/tests/ioh3420-test.c index b54c4b9f11..f6ca43cca7 100644 --- a/tests/ioh3420-test.c +++ b/tests/ioh3420-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/tests/ipmi-kcs-test.c b/tests/ipmi-kcs-test.c index a2354c10c7..693a6aacb5 100644 --- a/tests/ipmi-kcs-test.c +++ b/tests/ipmi-kcs-test.c @@ -24,8 +24,7 @@ #include "qemu/osdep.h" - -#include "libqtest.h" +#include "libqtest-single.h" #define IPMI_IRQ 5 diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c index b76457948b..be9aa92a61 100644 --- a/tests/ivshmem-test.c +++ b/tests/ivshmem-test.c @@ -100,7 +100,6 @@ static inline void write_mem(IVState *s, uint64_t off, static void cleanup_vm(IVState *s) { - assert(!global_qtest); g_free(s->dev); qtest_shutdown(s->qs); } @@ -388,7 +387,6 @@ static void test_ivshmem_hotplug(void) qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1"); - global_qtest = qts; /* TODO: Get rid of global_qtest here */ qtest_qmp_device_add(qts, "ivshmem-plain", "iv1", "{'addr': %s, 'memdev': 'mb1'}", stringify(PCI_SLOT_HP)); @@ -397,7 +395,6 @@ static void test_ivshmem_hotplug(void) } qtest_quit(qts); - global_qtest = NULL; } static void test_ivshmem_memdev(void) diff --git a/tests/libqos/e1000e.c b/tests/libqos/e1000e.c index 1d0592974e..560e7a2bb2 100644 --- a/tests/libqos/e1000e.c +++ b/tests/libqos/e1000e.c @@ -85,26 +85,32 @@ static uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg) void e1000e_tx_ring_push(QE1000E *d, void *descr) { + QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); uint32_t tail = e1000e_macreg_read(d, E1000E_TDT); uint32_t len = e1000e_macreg_read(d, E1000E_TDLEN) / E1000E_TXD_LEN; - memwrite(d->tx_ring + tail * E1000E_TXD_LEN, descr, E1000E_TXD_LEN); + qtest_memwrite(d_pci->pci_dev.bus->qts, d->tx_ring + tail * E1000E_TXD_LEN, + descr, E1000E_TXD_LEN); e1000e_macreg_write(d, E1000E_TDT, (tail + 1) % len); /* Read WB data for the packet transmitted */ - memread(d->tx_ring + tail * E1000E_TXD_LEN, descr, E1000E_TXD_LEN); + qtest_memread(d_pci->pci_dev.bus->qts, d->tx_ring + tail * E1000E_TXD_LEN, + descr, E1000E_TXD_LEN); } void e1000e_rx_ring_push(QE1000E *d, void *descr) { + QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); uint32_t tail = e1000e_macreg_read(d, E1000E_RDT); uint32_t len = e1000e_macreg_read(d, E1000E_RDLEN) / E1000E_RXD_LEN; - memwrite(d->rx_ring + tail * E1000E_RXD_LEN, descr, E1000E_RXD_LEN); + qtest_memwrite(d_pci->pci_dev.bus->qts, d->rx_ring + tail * E1000E_RXD_LEN, + descr, E1000E_RXD_LEN); e1000e_macreg_write(d, E1000E_RDT, (tail + 1) % len); /* Read WB data for the packet received */ - memread(d->rx_ring + tail * E1000E_RXD_LEN, descr, E1000E_RXD_LEN); + qtest_memread(d_pci->pci_dev.bus->qts, d->rx_ring + tail * E1000E_RXD_LEN, + descr, E1000E_RXD_LEN); } static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data) @@ -123,7 +129,7 @@ void e1000e_wait_isr(QE1000E *d, uint16_t msg_id) if (qpci_msix_pending(&d_pci->pci_dev, msg_id)) { return; } - clock_step(10000); + qtest_clock_step(d_pci->pci_dev.bus->qts, 10000); } while (g_get_monotonic_time() < end_time); g_error("Timeout expired"); diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c index 5f37b51129..d0047876a8 100644 --- a/tests/libqos/virtio-mmio.c +++ b/tests/libqos/virtio-mmio.c @@ -101,6 +101,18 @@ static bool qvirtio_mmio_get_config_isr_status(QVirtioDevice *d) return false; } +static void qvirtio_mmio_wait_config_isr_status(QVirtioDevice *d, + gint64 timeout_us) +{ + QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); + gint64 start_time = g_get_monotonic_time(); + + do { + g_assert(g_get_monotonic_time() - start_time <= timeout_us); + qtest_clock_step(dev->qts, 100); + } while (!qvirtio_mmio_get_config_isr_status(d)); +} + static void qvirtio_mmio_queue_select(QVirtioDevice *d, uint16_t index) { QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); @@ -179,7 +191,7 @@ const QVirtioBus qvirtio_mmio = { .get_status = qvirtio_mmio_get_status, .set_status = qvirtio_mmio_set_status, .get_queue_isr_status = qvirtio_mmio_get_queue_isr_status, - .get_config_isr_status = qvirtio_mmio_get_config_isr_status, + .wait_config_isr_status = qvirtio_mmio_wait_config_isr_status, .queue_select = qvirtio_mmio_queue_select, .get_queue_size = qvirtio_mmio_get_queue_size, .set_queue_address = qvirtio_mmio_set_queue_address, diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index 3f55c047a0..50499e75ef 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -175,6 +175,18 @@ static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d) } } +static void qvirtio_pci_wait_config_isr_status(QVirtioDevice *d, + gint64 timeout_us) +{ + QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); + gint64 start_time = g_get_monotonic_time(); + + do { + g_assert(g_get_monotonic_time() - start_time <= timeout_us); + qtest_clock_step(dev->pdev->bus->qts, 100); + } while (!qvirtio_pci_get_config_isr_status(d)); +} + static void qvirtio_pci_queue_select(QVirtioDevice *d, uint16_t index) { QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); @@ -257,7 +269,7 @@ const QVirtioBus qvirtio_pci = { .get_status = qvirtio_pci_get_status, .set_status = qvirtio_pci_set_status, .get_queue_isr_status = qvirtio_pci_get_queue_isr_status, - .get_config_isr_status = qvirtio_pci_get_config_isr_status, + .wait_config_isr_status = qvirtio_pci_wait_config_isr_status, .queue_select = qvirtio_pci_queue_select, .get_queue_size = qvirtio_pci_get_queue_size, .set_queue_address = qvirtio_pci_set_queue_address, diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index 91ce06954b..0ae9956fc8 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -82,13 +82,13 @@ void qvirtio_set_driver_ok(QVirtioDevice *d) VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_ACKNOWLEDGE); } -void qvirtio_wait_queue_isr(QVirtioDevice *d, +void qvirtio_wait_queue_isr(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, gint64 timeout_us) { gint64 start_time = g_get_monotonic_time(); for (;;) { - clock_step(100); + qtest_clock_step(qts, 100); if (d->bus->get_queue_isr_status(d, vq)) { return; } @@ -109,8 +109,8 @@ uint8_t qvirtio_wait_status_byte_no_isr(QTestState *qts, QVirtioDevice *d, gint64 start_time = g_get_monotonic_time(); uint8_t val; - while ((val = readb(addr)) == 0xff) { - clock_step(100); + while ((val = qtest_readb(qts, addr)) == 0xff) { + qtest_clock_step(qts, 100); g_assert(!d->bus->get_queue_isr_status(d, vq)); g_assert(g_get_monotonic_time() - start_time <= timeout_us); } @@ -137,7 +137,7 @@ void qvirtio_wait_used_elem(QTestState *qts, QVirtioDevice *d, for (;;) { uint32_t got_desc_idx; - clock_step(100); + qtest_clock_step(qts, 100); if (d->bus->get_queue_isr_status(d, vq) && qvirtqueue_get_buf(qts, vq, &got_desc_idx, len)) { @@ -151,15 +151,7 @@ void qvirtio_wait_used_elem(QTestState *qts, QVirtioDevice *d, void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us) { - gint64 start_time = g_get_monotonic_time(); - - for (;;) { - clock_step(100); - if (d->bus->get_config_isr_status(d)) { - return; - } - g_assert(g_get_monotonic_time() - start_time <= timeout_us); - } + d->bus->wait_config_isr_status(d, timeout_us); } void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq, diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h index 037176dbd8..2cb2448f46 100644 --- a/tests/libqos/virtio.h +++ b/tests/libqos/virtio.h @@ -69,8 +69,8 @@ struct QVirtioBus { /* Get the queue ISR status of the device */ bool (*get_queue_isr_status)(QVirtioDevice *d, QVirtQueue *vq); - /* Get the configuration ISR status of the device */ - bool (*get_config_isr_status)(QVirtioDevice *d); + /* Wait for the configuration ISR status of the device */ + void (*wait_config_isr_status)(QVirtioDevice *d, gint64 timeout_us); /* Select a queue to work on */ void (*queue_select)(QVirtioDevice *d, uint16_t index); @@ -112,7 +112,7 @@ void qvirtio_set_acknowledge(QVirtioDevice *d); void qvirtio_set_driver(QVirtioDevice *d); void qvirtio_set_driver_ok(QVirtioDevice *d); -void qvirtio_wait_queue_isr(QVirtioDevice *d, +void qvirtio_wait_queue_isr(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, gint64 timeout_us); uint8_t qvirtio_wait_status_byte_no_isr(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, diff --git a/tests/libqtest-single.h b/tests/libqtest-single.h new file mode 100644 index 0000000000..6f1bb1331c --- /dev/null +++ b/tests/libqtest-single.h @@ -0,0 +1,315 @@ +/* + * QTest - wrappers for test with single QEMU instances + * + * Copyright IBM, Corp. 2012 + * Copyright Red Hat, Inc. 2012 + * Copyright SUSE LINUX Products GmbH 2013 + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef LIBQTEST_SINGLE_H +#define LIBQTEST_SINGLE_H + +#include "libqtest.h" + +QTestState *global_qtest __attribute__((common, weak)); + +/** + * qtest_start: + * @args: other arguments to pass to QEMU + * + * Start QEMU and assign the resulting #QTestState to a global variable. + * The global variable is used by "shortcut" functions documented below. + * + * Returns: #QTestState instance. + */ +static inline QTestState *qtest_start(const char *args) +{ + global_qtest = qtest_init(args); + return global_qtest; +} + +/** + * qtest_end: + * + * Shut down the QEMU process started by qtest_start(). + */ +static inline void qtest_end(void) +{ + if (!global_qtest) { + return; + } + qtest_quit(global_qtest); + global_qtest = NULL; +} + +/** + * qmp: + * @fmt...: QMP message to send to qemu, formatted like + * qobject_from_jsonf_nofail(). See parse_escape() for what's + * supported after '%'. + * + * Sends a QMP message to QEMU and returns the response. + */ +GCC_FMT_ATTR(1, 2) +static inline QDict *qmp(const char *fmt, ...) +{ + va_list ap; + QDict *response; + + va_start(ap, fmt); + response = qtest_vqmp(global_qtest, fmt, ap); + va_end(ap); + return response; +} + +/** + * qmp_eventwait: + * @s: #event event to wait for. + * + * Continuously polls for QMP responses until it receives the desired event. + */ +static inline void qmp_eventwait(const char *event) +{ + return qtest_qmp_eventwait(global_qtest, event); +} + +/** + * get_irq: + * @num: Interrupt to observe. + * + * Returns: The level of the @num interrupt. + */ +static inline bool get_irq(int num) +{ + return qtest_get_irq(global_qtest, num); +} + +/** + * outb: + * @addr: I/O port to write to. + * @value: Value being written. + * + * Write an 8-bit value to an I/O port. + */ +static inline void outb(uint16_t addr, uint8_t value) +{ + qtest_outb(global_qtest, addr, value); +} + +/** + * outw: + * @addr: I/O port to write to. + * @value: Value being written. + * + * Write a 16-bit value to an I/O port. + */ +static inline void outw(uint16_t addr, uint16_t value) +{ + qtest_outw(global_qtest, addr, value); +} + +/** + * outl: + * @addr: I/O port to write to. + * @value: Value being written. + * + * Write a 32-bit value to an I/O port. + */ +static inline void outl(uint16_t addr, uint32_t value) +{ + qtest_outl(global_qtest, addr, value); +} + +/** + * inb: + * @addr: I/O port to read from. + * + * Reads an 8-bit value from an I/O port. + * + * Returns: Value read. + */ +static inline uint8_t inb(uint16_t addr) +{ + return qtest_inb(global_qtest, addr); +} + +/** + * inw: + * @addr: I/O port to read from. + * + * Reads a 16-bit value from an I/O port. + * + * Returns: Value read. + */ +static inline uint16_t inw(uint16_t addr) +{ + return qtest_inw(global_qtest, addr); +} + +/** + * inl: + * @addr: I/O port to read from. + * + * Reads a 32-bit value from an I/O port. + * + * Returns: Value read. + */ +static inline uint32_t inl(uint16_t addr) +{ + return qtest_inl(global_qtest, addr); +} + +/** + * writeb: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes an 8-bit value to guest memory. + */ +static inline void writeb(uint64_t addr, uint8_t value) +{ + qtest_writeb(global_qtest, addr, value); +} + +/** + * writew: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 16-bit value to guest memory. + */ +static inline void writew(uint64_t addr, uint16_t value) +{ + qtest_writew(global_qtest, addr, value); +} + +/** + * writel: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 32-bit value to guest memory. + */ +static inline void writel(uint64_t addr, uint32_t value) +{ + qtest_writel(global_qtest, addr, value); +} + +/** + * writeq: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 64-bit value to guest memory. + */ +static inline void writeq(uint64_t addr, uint64_t value) +{ + qtest_writeq(global_qtest, addr, value); +} + +/** + * readb: + * @addr: Guest address to read from. + * + * Reads an 8-bit value from guest memory. + * + * Returns: Value read. + */ +static inline uint8_t readb(uint64_t addr) +{ + return qtest_readb(global_qtest, addr); +} + +/** + * readw: + * @addr: Guest address to read from. + * + * Reads a 16-bit value from guest memory. + * + * Returns: Value read. + */ +static inline uint16_t readw(uint64_t addr) +{ + return qtest_readw(global_qtest, addr); +} + +/** + * readl: + * @addr: Guest address to read from. + * + * Reads a 32-bit value from guest memory. + * + * Returns: Value read. + */ +static inline uint32_t readl(uint64_t addr) +{ + return qtest_readl(global_qtest, addr); +} + +/** + * readq: + * @addr: Guest address to read from. + * + * Reads a 64-bit value from guest memory. + * + * Returns: Value read. + */ +static inline uint64_t readq(uint64_t addr) +{ + return qtest_readq(global_qtest, addr); +} + +/** + * memread: + * @addr: Guest address to read from. + * @data: Pointer to where memory contents will be stored. + * @size: Number of bytes to read. + * + * Read guest memory into a buffer. + */ +static inline void memread(uint64_t addr, void *data, size_t size) +{ + qtest_memread(global_qtest, addr, data, size); +} + +/** + * memwrite: + * @addr: Guest address to write to. + * @data: Pointer to the bytes that will be written to guest memory. + * @size: Number of bytes to write. + * + * Write a buffer to guest memory. + */ +static inline void memwrite(uint64_t addr, const void *data, size_t size) +{ + qtest_memwrite(global_qtest, addr, data, size); +} + +/** + * clock_step_next: + * + * Advance the QEMU_CLOCK_VIRTUAL to the next deadline. + * + * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds. + */ +static inline int64_t clock_step_next(void) +{ + return qtest_clock_step_next(global_qtest); +} + +/** + * clock_step: + * @step: Number of nanoseconds to advance the clock by. + * + * Advance the QEMU_CLOCK_VIRTUAL by @step nanoseconds. + * + * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds. + */ +static inline int64_t clock_step(int64_t step) +{ + return qtest_clock_step(global_qtest, step); +} + +#endif diff --git a/tests/libqtest.c b/tests/libqtest.c index 2713b86cf7..0a6b91737e 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -35,8 +35,6 @@ #define SOCKET_TIMEOUT 50 #define SOCKET_MAX_FDS 16 -QTestState *global_qtest; - struct QTestState { int fd; @@ -1106,17 +1104,6 @@ void qtest_memset(QTestState *s, uint64_t addr, uint8_t pattern, size_t size) qtest_rsp(s, 0); } -QDict *qmp(const char *fmt, ...) -{ - va_list ap; - QDict *response; - - va_start(ap, fmt); - response = qtest_vqmp(global_qtest, fmt, ap); - va_end(ap); - return response; -} - void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...) { va_list ap; diff --git a/tests/libqtest.h b/tests/libqtest.h index 07ea35867c..c8cffe5d68 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -22,8 +22,6 @@ typedef struct QTestState QTestState; -extern QTestState *global_qtest; - /** * qtest_initf: * @fmt...: Format for creating other arguments to pass to QEMU, formatted @@ -629,45 +627,6 @@ void qtest_add_data_func_full(const char *str, void *data, void qtest_add_abrt_handler(GHookFunc fn, const void *data); /** - * qtest_start: - * @args: other arguments to pass to QEMU - * - * Start QEMU and assign the resulting #QTestState to a global variable. - * The global variable is used by "shortcut" functions documented below. - * - * Returns: #QTestState instance. - */ -static inline QTestState *qtest_start(const char *args) -{ - global_qtest = qtest_init(args); - return global_qtest; -} - -/** - * qtest_end: - * - * Shut down the QEMU process started by qtest_start(). - */ -static inline void qtest_end(void) -{ - if (!global_qtest) { - return; - } - qtest_quit(global_qtest); - global_qtest = NULL; -} - -/** - * qmp: - * @fmt...: QMP message to send to qemu, formatted like - * qobject_from_jsonf_nofail(). See parse_escape() for what's - * supported after '%'. - * - * Sends a QMP message to QEMU and returns the response. - */ -QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2); - -/** * qtest_qmp_assert_success: * @qts: QTestState instance to operate on * @fmt...: QMP message to send to qemu, formatted like @@ -680,254 +639,6 @@ QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2); void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...) GCC_FMT_ATTR(2, 3); -/* - * qmp_eventwait: - * @s: #event event to wait for. - * - * Continuously polls for QMP responses until it receives the desired event. - */ -static inline void qmp_eventwait(const char *event) -{ - return qtest_qmp_eventwait(global_qtest, event); -} - -/** - * get_irq: - * @num: Interrupt to observe. - * - * Returns: The level of the @num interrupt. - */ -static inline bool get_irq(int num) -{ - return qtest_get_irq(global_qtest, num); -} - -/** - * outb: - * @addr: I/O port to write to. - * @value: Value being written. - * - * Write an 8-bit value to an I/O port. - */ -static inline void outb(uint16_t addr, uint8_t value) -{ - qtest_outb(global_qtest, addr, value); -} - -/** - * outw: - * @addr: I/O port to write to. - * @value: Value being written. - * - * Write a 16-bit value to an I/O port. - */ -static inline void outw(uint16_t addr, uint16_t value) -{ - qtest_outw(global_qtest, addr, value); -} - -/** - * outl: - * @addr: I/O port to write to. - * @value: Value being written. - * - * Write a 32-bit value to an I/O port. - */ -static inline void outl(uint16_t addr, uint32_t value) -{ - qtest_outl(global_qtest, addr, value); -} - -/** - * inb: - * @addr: I/O port to read from. - * - * Reads an 8-bit value from an I/O port. - * - * Returns: Value read. - */ -static inline uint8_t inb(uint16_t addr) -{ - return qtest_inb(global_qtest, addr); -} - -/** - * inw: - * @addr: I/O port to read from. - * - * Reads a 16-bit value from an I/O port. - * - * Returns: Value read. - */ -static inline uint16_t inw(uint16_t addr) -{ - return qtest_inw(global_qtest, addr); -} - -/** - * inl: - * @addr: I/O port to read from. - * - * Reads a 32-bit value from an I/O port. - * - * Returns: Value read. - */ -static inline uint32_t inl(uint16_t addr) -{ - return qtest_inl(global_qtest, addr); -} - -/** - * writeb: - * @addr: Guest address to write to. - * @value: Value being written. - * - * Writes an 8-bit value to guest memory. - */ -static inline void writeb(uint64_t addr, uint8_t value) -{ - qtest_writeb(global_qtest, addr, value); -} - -/** - * writew: - * @addr: Guest address to write to. - * @value: Value being written. - * - * Writes a 16-bit value to guest memory. - */ -static inline void writew(uint64_t addr, uint16_t value) -{ - qtest_writew(global_qtest, addr, value); -} - -/** - * writel: - * @addr: Guest address to write to. - * @value: Value being written. - * - * Writes a 32-bit value to guest memory. - */ -static inline void writel(uint64_t addr, uint32_t value) -{ - qtest_writel(global_qtest, addr, value); -} - -/** - * writeq: - * @addr: Guest address to write to. - * @value: Value being written. - * - * Writes a 64-bit value to guest memory. - */ -static inline void writeq(uint64_t addr, uint64_t value) -{ - qtest_writeq(global_qtest, addr, value); -} - -/** - * readb: - * @addr: Guest address to read from. - * - * Reads an 8-bit value from guest memory. - * - * Returns: Value read. - */ -static inline uint8_t readb(uint64_t addr) -{ - return qtest_readb(global_qtest, addr); -} - -/** - * readw: - * @addr: Guest address to read from. - * - * Reads a 16-bit value from guest memory. - * - * Returns: Value read. - */ -static inline uint16_t readw(uint64_t addr) -{ - return qtest_readw(global_qtest, addr); -} - -/** - * readl: - * @addr: Guest address to read from. - * - * Reads a 32-bit value from guest memory. - * - * Returns: Value read. - */ -static inline uint32_t readl(uint64_t addr) -{ - return qtest_readl(global_qtest, addr); -} - -/** - * readq: - * @addr: Guest address to read from. - * - * Reads a 64-bit value from guest memory. - * - * Returns: Value read. - */ -static inline uint64_t readq(uint64_t addr) -{ - return qtest_readq(global_qtest, addr); -} - -/** - * memread: - * @addr: Guest address to read from. - * @data: Pointer to where memory contents will be stored. - * @size: Number of bytes to read. - * - * Read guest memory into a buffer. - */ -static inline void memread(uint64_t addr, void *data, size_t size) -{ - qtest_memread(global_qtest, addr, data, size); -} - -/** - * memwrite: - * @addr: Guest address to write to. - * @data: Pointer to the bytes that will be written to guest memory. - * @size: Number of bytes to write. - * - * Write a buffer to guest memory. - */ -static inline void memwrite(uint64_t addr, const void *data, size_t size) -{ - qtest_memwrite(global_qtest, addr, data, size); -} - -/** - * clock_step_next: - * - * Advance the QEMU_CLOCK_VIRTUAL to the next deadline. - * - * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds. - */ -static inline int64_t clock_step_next(void) -{ - return qtest_clock_step_next(global_qtest); -} - -/** - * clock_step: - * @step: Number of nanoseconds to advance the clock by. - * - * Advance the QEMU_CLOCK_VIRTUAL by @step nanoseconds. - * - * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds. - */ -static inline int64_t clock_step(int64_t step) -{ - return qtest_clock_step(global_qtest, step); -} - QDict *qmp_fd_receive(int fd); void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, const char *fmt, va_list ap) GCC_FMT_ATTR(4, 0); diff --git a/tests/m25p80-test.c b/tests/m25p80-test.c index 055f7246a8..50c6b79fb3 100644 --- a/tests/m25p80-test.c +++ b/tests/m25p80-test.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "qemu/bswap.h" -#include "libqtest.h" +#include "libqtest-single.h" /* * ASPEED SPI Controller registers diff --git a/tests/migration-test.c b/tests/migration-test.c index b87ba99a9e..a9f81cc185 100644 --- a/tests/migration-test.c +++ b/tests/migration-test.c @@ -490,7 +490,7 @@ static void migrate(QTestState *who, const char *uri, const char *fmt, ...) g_assert(!qdict_haskey(args, "uri")); qdict_put_str(args, "uri", uri); - rsp = qmp("{ 'execute': 'migrate', 'arguments': %p}", args); + rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args); g_assert(qdict_haskey(rsp, "return")); qobject_unref(rsp); @@ -625,7 +625,7 @@ static int test_migrate_start(QTestState **from, QTestState **to, cmd_dst = tmp; } - *from = qtest_start(cmd_src); + *from = qtest_init(cmd_src); g_free(cmd_src); *to = qtest_init(cmd_dst); @@ -715,7 +715,7 @@ static void test_deprecated(void) { QTestState *from; - from = qtest_start("-machine none"); + from = qtest_init("-machine none"); deprecated_set_downtime(from, 0.12345); deprecated_set_speed(from, 12345); diff --git a/tests/pnv-xscom-test.c b/tests/pnv-xscom-test.c index 63d464048d..9fddc7d5f9 100644 --- a/tests/pnv-xscom-test.c +++ b/tests/pnv-xscom-test.c @@ -77,9 +77,15 @@ static void test_xscom_cfam_id(QTestState *qts, const PnvChip *chip) static void test_cfam_id(const void *data) { const PnvChip *chip = data; + const char *machine = "powernv8"; QTestState *qts; - qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model); + if (chip->chip_type == PNV_CHIP_POWER9) { + machine = "powernv9"; + } + + qts = qtest_initf("-M %s,accel=tcg -cpu %s", + machine, chip->cpu_model); test_xscom_cfam_id(qts, chip); qtest_quit(qts); } @@ -113,8 +119,14 @@ static void test_core(const void *data) { const PnvChip *chip = data; QTestState *qts; + const char *machine = "powernv8"; + + if (chip->chip_type == PNV_CHIP_POWER9) { + machine = "powernv9"; + } - qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model); + qts = qtest_initf("-M %s,accel=tcg -cpu %s", + machine, chip->cpu_model); test_xscom_core(qts, chip); qtest_quit(qts); } diff --git a/tests/qemu-iotests/002 b/tests/qemu-iotests/002 index fd413bce48..1a0d411df5 100755 --- a/tests/qemu-iotests/002 +++ b/tests/qemu-iotests/002 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto generic +_unsupported_imgopts "subformat=streamOptimized" size=128M diff --git a/tests/qemu-iotests/003 b/tests/qemu-iotests/003 index ccd3a39dfb..33eeade0de 100755 --- a/tests/qemu-iotests/003 +++ b/tests/qemu-iotests/003 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto generic +_unsupported_imgopts "subformat=streamOptimized" size=128M offset=67M diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005 index 9c7681c19b..58442762fe 100755 --- a/tests/qemu-iotests/005 +++ b/tests/qemu-iotests/005 @@ -43,7 +43,8 @@ _supported_fmt generic _supported_proto generic _supported_os Linux _unsupported_imgopts "subformat=twoGbMaxExtentFlat" \ - "subformat=twoGbMaxExtentSparse" + "subformat=twoGbMaxExtentSparse" \ + "subformat=streamOptimized" # vpc is limited to 127GB, so we can't test it here if [ "$IMGFMT" = "vpc" ]; then diff --git a/tests/qemu-iotests/009 b/tests/qemu-iotests/009 index 51b200db1d..4dc7d210f9 100755 --- a/tests/qemu-iotests/009 +++ b/tests/qemu-iotests/009 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto generic +_unsupported_imgopts "subformat=streamOptimized" size=6G diff --git a/tests/qemu-iotests/010 b/tests/qemu-iotests/010 index 48c533f632..df809b3088 100755 --- a/tests/qemu-iotests/010 +++ b/tests/qemu-iotests/010 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto generic +_unsupported_imgopts "subformat=streamOptimized" size=6G diff --git a/tests/qemu-iotests/011 b/tests/qemu-iotests/011 index 56f704b5b9..57b99ae4a9 100755 --- a/tests/qemu-iotests/011 +++ b/tests/qemu-iotests/011 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto generic +_unsupported_imgopts "subformat=streamOptimized" size=6G diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017 index 79875de454..0a4b854e65 100755 --- a/tests/qemu-iotests/017 +++ b/tests/qemu-iotests/017 @@ -41,7 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 vmdk qed _supported_proto generic _unsupported_proto vxhs -_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" +_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \ + "subformat=streamOptimized" TEST_OFFSETS="0 4294967296" diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018 index 78169838ba..c69ce09209 100755 --- a/tests/qemu-iotests/018 +++ b/tests/qemu-iotests/018 @@ -41,7 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 vmdk qed _supported_proto file _supported_os Linux -_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" +_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \ + "streamOptimized" TEST_OFFSETS="0 4294967296" diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019 index a56dd30bed..b4f5234609 100755 --- a/tests/qemu-iotests/019 +++ b/tests/qemu-iotests/019 @@ -47,7 +47,8 @@ _supported_proto file _supported_os Linux _unsupported_imgopts "subformat=monolithicFlat" \ "subformat=twoGbMaxExtentFlat" \ - "subformat=twoGbMaxExtentSparse" + "subformat=twoGbMaxExtentSparse" \ + "subformat=streamOptimized" TEST_OFFSETS="0 4294967296" CLUSTER_SIZE=65536 diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020 index 6b0ebb37d2..f41b92f35f 100755 --- a/tests/qemu-iotests/020 +++ b/tests/qemu-iotests/020 @@ -44,7 +44,8 @@ _supported_fmt qcow qcow2 vmdk qed _supported_proto file _unsupported_imgopts "subformat=monolithicFlat" \ "subformat=twoGbMaxExtentFlat" \ - "subformat=twoGbMaxExtentSparse" + "subformat=twoGbMaxExtentSparse" \ + "subformat=streamOptimized" TEST_OFFSETS="0 4294967296" diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026 index e30243608b..ffb18ab6b5 100755 --- a/tests/qemu-iotests/026 +++ b/tests/qemu-iotests/026 @@ -41,8 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # Currently only qcow2 supports rebasing _supported_fmt qcow2 _supported_proto file -_default_cache_mode "writethrough" -_supported_cache_modes "writethrough" "none" +_default_cache_mode writethrough +_supported_cache_modes writethrough none # The refcount table tests expect a certain minimum width for refcount entries # (so that the refcount table actually needs to grow); that minimum is 16 bits, # being the default refcount entry width. diff --git a/tests/qemu-iotests/027 b/tests/qemu-iotests/027 index 4cb638022a..494be0921f 100755 --- a/tests/qemu-iotests/027 +++ b/tests/qemu-iotests/027 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt vmdk qcow qcow2 qed _supported_proto generic +_unsupported_imgopts "subformat=streamOptimized" size=128M diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032 index 988a8c5d8f..8337a4d825 100755 --- a/tests/qemu-iotests/032 +++ b/tests/qemu-iotests/032 @@ -42,6 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # This works for any image format (though unlikely to segfault for raw) _supported_fmt generic _supported_proto generic +_unsupported_imgopts "subformat=streamOptimized" echo echo === Prepare image === diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033 index 362a48c0a0..8b40991d55 100755 --- a/tests/qemu-iotests/033 +++ b/tests/qemu-iotests/033 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto generic +_unsupported_imgopts "subformat=streamOptimized" size=128M diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034 index 324bed28c6..da4cea1571 100755 --- a/tests/qemu-iotests/034 +++ b/tests/qemu-iotests/034 @@ -41,7 +41,8 @@ _supported_proto file _supported_os Linux _unsupported_imgopts "subformat=monolithicFlat" \ "subformat=twoGbMaxExtentFlat" \ - "subformat=twoGbMaxExtentSparse" + "subformat=twoGbMaxExtentSparse" \ + "subformat=streamOptimized" CLUSTER_SIZE=4k size=128M diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037 index 4946b9be92..e6517acbd4 100755 --- a/tests/qemu-iotests/037 +++ b/tests/qemu-iotests/037 @@ -40,7 +40,8 @@ _supported_fmt qcow qcow2 vmdk qed _supported_proto file _unsupported_imgopts "subformat=monolithicFlat" \ "subformat=twoGbMaxExtentFlat" \ - "subformat=twoGbMaxExtentSparse" + "subformat=twoGbMaxExtentSparse" \ + "subformat=streamOptimized" CLUSTER_SIZE=4k size=128M diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 index 0d4e963bd4..7c730d94a7 100755 --- a/tests/qemu-iotests/039 +++ b/tests/qemu-iotests/039 @@ -42,8 +42,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file _supported_os Linux -_default_cache_mode "writethrough" -_supported_cache_modes "writethrough" +_default_cache_mode writethrough +_supported_cache_modes writethrough size=128M diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052 index 6e2ecbfe21..45a140910d 100755 --- a/tests/qemu-iotests/052 +++ b/tests/qemu-iotests/052 @@ -40,7 +40,7 @@ _supported_fmt generic _supported_proto file # Don't do O_DIRECT on tmpfs -_supported_cache_modes "writeback" "writethrough" "unsafe" +_supported_cache_modes writeback writethrough unsafe size=128M _make_test_img $size diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index 279aee6815..10bfbaecec 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -114,11 +114,41 @@ $QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2 echo echo "=== Testing monolithicFlat with internally generated JSON file name ===" + +echo '--- blkdebug ---' +# Should work, because bdrv_dirname() works fine with blkdebug IMGOPTS="subformat=monolithicFlat" _make_test_img 64M -$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" 2>&1 \ - | _filter_testdir | _filter_imgfmt +$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" \ + -c info \ + 2>&1 \ + | _filter_testdir | _filter_imgfmt | _filter_img_info _cleanup_test_img +echo '--- quorum ---' +# Should not work, because bdrv_dirname() does not work with quorum +IMGOPTS="subformat=monolithicFlat" _make_test_img 64M +cp "$TEST_IMG" "$TEST_IMG.orig" + +filename="json:{ + \"driver\": \"$IMGFMT\", + \"file\": { + \"driver\": \"quorum\", + \"children\": [ { + \"driver\": \"file\", + \"filename\": \"$TEST_IMG\" + }, { + \"driver\": \"file\", + \"filename\": \"$TEST_IMG.orig\" + } ], + \"vote-threshold\": 1 + } }" + +filename=$(echo "$filename" | tr '\n' ' ' | sed -e 's/\s\+/ /g') +$QEMU_IMG info "$filename" 2>&1 \ + | sed -e "s/'json:[^']*'/\$QUORUM_FILE/g" \ + | _filter_testdir | _filter_imgfmt | _filter_img_info + + echo echo "=== Testing version 3 ===" _use_sample_img iotest-version3.vmdk.bz2 diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out index 4fab42a28c..39bf7e211d 100644 --- a/tests/qemu-iotests/059.out +++ b/tests/qemu-iotests/059.out @@ -13,21 +13,21 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too big === Testing monolithicFlat creation and opening === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 2 GiB (2147483648 bytes) === Testing monolithicFlat with zeroed_grain === qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 === Testing big twoGbMaxExtentFlat === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMaxExtentFlat +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 image: TEST_DIR/t.vmdk file format: vmdk virtual size: 0.977 TiB (1073741824000 bytes) -disk size: 16 KiB +disk size: 1.97 MiB Format specific information: cid: XXXXXXXX parent cid: XXXXXXXX @@ -2038,7 +2038,7 @@ Format specific information: qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Invalid extent line: RW 12582912 VMFS "dummy.IMGFMT" 1 === Testing truncated sparse === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 subformat=monolithicSparse +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at least 13172736 bytes === Converting to streamOptimized from image with small cluster size=== @@ -2049,8 +2049,14 @@ wrote 512/512 bytes at offset 10240 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing monolithicFlat with internally generated JSON file name === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 subformat=monolithicFlat -qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "read_aio"}' +--- blkdebug --- +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +format name: IMGFMT +cluster size: 0 bytes +vm state offset: 0 bytes +--- quorum --- +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-img: Could not open $QUORUM_FILE: Cannot use relative paths with VMDK descriptor file $QUORUM_FILE: Cannot generate a base directory for quorum nodes === Testing version 3 === image: TEST_DIR/iotest-version3.IMGFMT @@ -2259,7 +2265,7 @@ read 512/512 bytes at offset 64931328 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing 4TB monolithicFlat creation and IO === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4398046511104 subformat=monolithicFlat +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4398046511104 image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 4 TiB (4398046511104 bytes) @@ -2333,7 +2339,7 @@ read 1024/1024 bytes at offset 966367641600 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Testing qemu-img map on extents === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 subformat=monolithicSparse +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 wrote 1024/1024 bytes at offset 65024 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1024/1024 bytes at offset 2147483136 @@ -2344,7 +2350,7 @@ Offset Length Mapped to File 0 0x20000 0x3f0000 TEST_DIR/t.vmdk 0x7fff0000 0x20000 0x410000 TEST_DIR/t.vmdk 0x140000000 0x10000 0x430000 TEST_DIR/t.vmdk -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 subformat=twoGbMaxExtentSparse +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 wrote 1024/1024 bytes at offset 65024 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1024/1024 bytes at offset 2147483136 diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063 index fe4892e467..7cf0427af4 100755 --- a/tests/qemu-iotests/063 +++ b/tests/qemu-iotests/063 @@ -43,7 +43,8 @@ _supported_fmt qcow qcow2 vmdk qed raw _supported_proto file _unsupported_imgopts "subformat=monolithicFlat" \ "subformat=twoGbMaxExtentFlat" \ - "subformat=twoGbMaxExtentSparse" + "subformat=twoGbMaxExtentSparse" \ + "subformat=streamOptimized" _make_test_img 4M diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 index 1cca9233d0..fab526666b 100755 --- a/tests/qemu-iotests/071 +++ b/tests/qemu-iotests/071 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file +_require_drivers blkdebug blkverify do_run_qemu() { diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072 index 661b36da2d..f0b73e7e65 100755 --- a/tests/qemu-iotests/072 +++ b/tests/qemu-iotests/072 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt vpc vmdk vhdx vdi qed qcow2 qcow _supported_proto file +_unsupported_imgopts "subformat=streamOptimized" IMG_SIZE=64M diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081 index c418bab093..85acdf76d4 100755 --- a/tests/qemu-iotests/081 +++ b/tests/qemu-iotests/081 @@ -41,6 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt raw _supported_proto file _supported_os Linux +_require_drivers quorum do_run_qemu() { @@ -55,9 +56,6 @@ run_qemu() | _filter_qemu_io | _filter_generated_node_ids } -test_quorum=$($QEMU_IMG --help|grep quorum) -[ "$test_quorum" = "" ] && _supported_fmt quorum - quorum="driver=raw,file.driver=quorum,file.vote-threshold=2" quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw" quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw" diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091 index d62ef18a02..f4b44659ae 100755 --- a/tests/qemu-iotests/091 +++ b/tests/qemu-iotests/091 @@ -46,8 +46,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file _supported_os Linux -_default_cache_mode "none" -_supported_cache_modes "writethrough" "none" "writeback" +_default_cache_mode none +_supported_cache_modes writethrough none writeback size=1G diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099 index ae02f27afe..c3cf66798a 100755 --- a/tests/qemu-iotests/099 +++ b/tests/qemu-iotests/099 @@ -42,6 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 qed vdi vhdx vmdk vpc _supported_proto file _supported_os Linux +_require_drivers blkdebug blkverify _unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \ "subformat=twoGbMaxExtentSparse" diff --git a/tests/qemu-iotests/105 b/tests/qemu-iotests/105 index 3346e8cb25..4d55a2d3ef 100755 --- a/tests/qemu-iotests/105 +++ b/tests/qemu-iotests/105 @@ -39,7 +39,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 vmdk vhdx qed _supported_proto generic _unsupported_imgopts "subformat=twoGbMaxExtentFlat" \ - "subformat=twoGbMaxExtentSparse" + "subformat=twoGbMaxExtentSparse" \ + "subformat=streamOptimized" echo echo "creating large image" diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110 index 2cdc7c8a72..2ef516baf1 100755 --- a/tests/qemu-iotests/110 +++ b/tests/qemu-iotests/110 @@ -40,7 +40,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # Any format supporting backing files _supported_fmt qed qcow qcow2 vmdk _supported_proto file -_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" +_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \ + "subformat=twoGbMaxExtentSparse" TEST_IMG_REL=$(basename "$TEST_IMG") diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120 index e9b4fbb009..2931a7550f 100755 --- a/tests/qemu-iotests/120 +++ b/tests/qemu-iotests/120 @@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto file _unsupported_fmt luks +_require_drivers raw _make_test_img 64M diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126 index 9b0dcf9255..b7fce1e59d 100755 --- a/tests/qemu-iotests/126 +++ b/tests/qemu-iotests/126 @@ -33,6 +33,8 @@ status=1 # failure is the default! # Needs backing file support _supported_fmt qcow qcow2 qed vmdk +_unsupported_imgopts "subformat=monolithicFlat" \ + "subformat=twoGbMaxExtentFlat" # This is the default protocol (and we want to test the difference between # colons which separate a protocol prefix from the rest and colons which are # just part of the filename, so we cannot test protocols which require a prefix) diff --git a/tests/qemu-iotests/150.out b/tests/qemu-iotests/150.out.qcow2 index 2a54e8dcfa..2a54e8dcfa 100644 --- a/tests/qemu-iotests/150.out +++ b/tests/qemu-iotests/150.out.qcow2 diff --git a/tests/qemu-iotests/150.out.raw b/tests/qemu-iotests/150.out.raw new file mode 100644 index 0000000000..3cdc7727a5 --- /dev/null +++ b/tests/qemu-iotests/150.out.raw @@ -0,0 +1,12 @@ +QA output created by 150 + +=== Mapping sparse conversion === + +Offset Length File +0 0x1000 TEST_DIR/t.IMGFMT + +=== Mapping non-sparse conversion === + +Offset Length File +0 0x100000 TEST_DIR/t.IMGFMT +*** done diff --git a/tests/qemu-iotests/162 b/tests/qemu-iotests/162 index 4e5ed74fd5..2d719afbed 100755 --- a/tests/qemu-iotests/162 +++ b/tests/qemu-iotests/162 @@ -39,9 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.filter _supported_fmt generic - -test_ssh=$($QEMU_IMG --help | grep '^Supported formats:.* ssh\( \|$\)') -[ "$test_ssh" = "" ] && _notrun "ssh support required" +_require_drivers ssh echo echo '=== NBD ===' diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175 index 51e62c8276..55db2803ed 100755 --- a/tests/qemu-iotests/175 +++ b/tests/qemu-iotests/175 @@ -37,14 +37,33 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # the file size. This function hides the resulting difference in the # stat -c '%b' output. # Parameter 1: Number of blocks an empty file occupies -# Parameter 2: Image size in bytes +# Parameter 2: Minimal number of blocks in an image +# Parameter 3: Image size in bytes _filter_blocks() { extra_blocks=$1 - img_size=$2 + min_blocks=$2 + img_size=$3 - sed -e "s/blocks=$extra_blocks\\(\$\\|[^0-9]\\)/nothing allocated/" \ - -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/everything allocated/" + sed -e "s/blocks=$min_blocks\\(\$\\|[^0-9]\\)/min allocation/" \ + -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/max allocation/" +} + +# Resize image using block_resize. +# Parameter 1: image path +# Parameter 2: new size +_block_resize() +{ + local path=$1 + local size=$2 + + $QEMU -qmp stdio -nographic -nodefaults \ + -blockdev file,node-name=file,filename=$path,cache.direct=on \ + <<EOF +{'execute': 'qmp_capabilities'} +{'execute': 'block_resize', 'arguments': {'node-name': 'file', 'size': $size}} +{'execute': 'quit'} +EOF } # get standard environment, filters and checks @@ -55,21 +74,37 @@ _supported_fmt raw _supported_proto file _supported_os Linux +_default_cache_mode none +_supported_cache_modes none directsync + size=$((1 * 1024 * 1024)) touch "$TEST_DIR/empty" extra_blocks=$(stat -c '%b' "$TEST_DIR/empty") +# We always write the first byte; check how many blocks this filesystem +# allocates to match empty image alloation. +printf "\0" > "$TEST_DIR/empty" +min_blocks=$(stat -c '%b' "$TEST_DIR/empty") + echo echo "== creating image with default preallocation ==" _make_test_img $size | _filter_imgfmt -stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size +stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size for mode in off full falloc; do echo echo "== creating image with preallocation $mode ==" IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt - stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size + stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size +done + +for new_size in 4096 1048576; do + echo + echo "== resize empty image with block_resize ==" + _make_test_img 0 | _filter_imgfmt + _block_resize $TEST_IMG $new_size >/dev/null + stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $new_size done # success, all done diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out index 6d9a5ed84e..39c2ee0f62 100644 --- a/tests/qemu-iotests/175.out +++ b/tests/qemu-iotests/175.out @@ -2,17 +2,25 @@ QA output created by 175 == creating image with default preallocation == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 -size=1048576, nothing allocated +size=1048576, min allocation == creating image with preallocation off == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off -size=1048576, nothing allocated +size=1048576, min allocation == creating image with preallocation full == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full -size=1048576, everything allocated +size=1048576, max allocation == creating image with preallocation falloc == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc -size=1048576, everything allocated +size=1048576, max allocation + +== resize empty image with block_resize == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0 +size=4096, min allocation + +== resize empty image with block_resize == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0 +size=1048576, min allocation *** done diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2 index 55a8dc926f..9e7d8c44df 100644 --- a/tests/qemu-iotests/178.out.qcow2 +++ b/tests/qemu-iotests/178.out.qcow2 @@ -101,7 +101,7 @@ converted image file size in bytes: 196608 == raw input image with data (human) == Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824 -required size: 393216 +required size: 458752 fully allocated size: 1074135040 wrote 512/512 bytes at offset 512 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -257,7 +257,7 @@ converted image file size in bytes: 196608 Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824 { - "required": 393216, + "required": 458752, "fully-allocated": 1074135040 } wrote 512/512 bytes at offset 512 diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184 index cb0c181228..33dd8d2a4f 100755 --- a/tests/qemu-iotests/184 +++ b/tests/qemu-iotests/184 @@ -33,6 +33,7 @@ trap "exit \$status" 0 1 2 3 15 . ./common.filter _supported_os Linux +_require_drivers throttle do_run_qemu() { diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186 index 5f6b18c150..3ea0442d44 100755 --- a/tests/qemu-iotests/186 +++ b/tests/qemu-iotests/186 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file +_require_drivers null-co if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then _notrun "Requires a PC machine" diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 index 383d7d7f61..1d4f6786db 100755 --- a/tests/qemu-iotests/197 +++ b/tests/qemu-iotests/197 @@ -53,6 +53,7 @@ _supported_fmt generic _supported_proto generic # LUKS support may be possible, but it complicates things. _unsupported_fmt luks +_unsupported_imgopts "subformat=streamOptimized" echo echo '=== Copy-on-read ===' diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215 index 958c14f5a0..2eb377d682 100755 --- a/tests/qemu-iotests/215 +++ b/tests/qemu-iotests/215 @@ -50,6 +50,7 @@ _supported_fmt generic _supported_proto generic # LUKS support may be possible, but it complicates things. _unsupported_fmt luks +_unsupported_imgopts "subformat=streamOptimized" echo echo '=== Copy-on-read ===' diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out index 9f9dd52bb0..dca024a0c3 100644 --- a/tests/qemu-iotests/221.out +++ b/tests/qemu-iotests/221.out @@ -3,14 +3,18 @@ QA output created by 221 === Check mapping of unaligned raw image === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537 -[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] -[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] wrote 1/1 bytes at offset 65536 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, +[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, { "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, { "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] -[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, +[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, { "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, { "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] *** done diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index d5201b2356..5d00398c11 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -40,7 +40,7 @@ exports available: 0 exports available: 2 export: 'n' size: 4194304 - flags: 0x4ef ( readonly flush fua trim zeroes df cache ) + flags: 0x58f ( readonly flush fua df multi cache ) min block: 1 opt block: 4096 max block: 33554432 @@ -49,7 +49,7 @@ exports available: 2 qemu:dirty-bitmap:b export: 'n2' size: 4194304 - flags: 0x4ed ( flush fua trim zeroes df cache ) + flags: 0xced ( flush fua trim zeroes df cache fast-zero ) min block: 1 opt block: 4096 max block: 33554432 diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out index 9b46284ab0..24321efa11 100644 --- a/tests/qemu-iotests/233.out +++ b/tests/qemu-iotests/233.out @@ -20,10 +20,10 @@ qemu-nbd: Denied by server for option 5 (starttls) server reported: TLS not configured == check plain client to TLS server fails == -qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 8 (structured reply) -server reported: Option 0x8 not permitted before TLS -qemu-nbd: TLS negotiation required before option 8 (structured reply) -server reported: Option 0x8 not permitted before TLS +qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 7 (go) +server reported: Option 0x7 not permitted before TLS +qemu-nbd: TLS negotiation required before option 3 (list) +server reported: Option 0x3 not permitted before TLS == check TLS works == image: nbd://127.0.0.1:PORT @@ -37,7 +37,7 @@ disk size: unavailable exports available: 1 export: '' size: 67108864 - flags: 0x4ed ( flush fua trim zeroes df cache ) + flags: 0xced ( flush fua trim zeroes df cache fast-zero ) min block: 1 opt block: 4096 max block: 33554432 diff --git a/tests/qemu-iotests/251 b/tests/qemu-iotests/251 index 13f85de9cd..7918ba3559 100755 --- a/tests/qemu-iotests/251 +++ b/tests/qemu-iotests/251 @@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt generic _supported_proto file _supported_os Linux +_unsupported_imgopts "subformat=streamOptimized" if [ "$IMGOPTSSYNTAX" = "true" ]; then # We use json:{} filenames here, so we cannot work with additional options. diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out index 607c0baa0b..3d08b305d7 100644 --- a/tests/qemu-iotests/253.out +++ b/tests/qemu-iotests/253.out @@ -3,12 +3,16 @@ QA output created by 253 === Check mapping of unaligned raw image === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575 -[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] -[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] wrote 65535/65535 bytes at offset 983040 63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, +[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, { "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] -[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, +[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, { "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] *** done diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index c24874ff4a..a58232eefb 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -581,13 +581,13 @@ export QEMU_PROG="$(type -p "$QEMU_PROG")" case "$QEMU_PROG" in *qemu-system-arm|*qemu-system-aarch64) - export QEMU_OPTIONS="-nodefaults -machine virt,accel=qtest" + export QEMU_OPTIONS="-nodefaults -display none -machine virt,accel=qtest" ;; *qemu-system-tricore) - export QEMU_OPTIONS="-nodefaults -machine tricore_testboard,accel=qtest" + export QEMU_OPTIONS="-nodefaults -display none -machine tricore_testboard,accel=qtest" ;; *) - export QEMU_OPTIONS="-nodefaults -machine accel=qtest" + export QEMU_OPTIONS="-nodefaults -display none -machine accel=qtest" ;; esac diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 8e9235d6fe..445a1c23e0 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -130,8 +130,8 @@ _filter_img_create() -e "s# compat6=\\(on\\|off\\)##g" \ -e "s# static=\\(on\\|off\\)##g" \ -e "s# zeroed_grain=\\(on\\|off\\)##g" \ - -e "s# subformat='[^']*'##g" \ - -e "s# adapter_type='[^']*'##g" \ + -e "s# subformat=[^ ]*##g" \ + -e "s# adapter_type=[^ ]*##g" \ -e "s# hwversion=[^ ]*##g" \ -e "s# lazy_refcounts=\\(on\\|off\\)##g" \ -e "s# block_size=[0-9]\\+##g" \ diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 5502c3da2f..ee20be8920 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -520,5 +520,19 @@ _require_command() [ -x "$c" ] || _notrun "$1 utility required, skipped this test" } +# Check that a set of drivers has been whitelisted in the QEMU binary +# +_require_drivers() +{ + available=$($QEMU -drive format=help | \ + sed -e '/Supported formats:/!d' -e 's/Supported formats://') + for driver + do + if ! echo "$available" | grep -q " $driver\( \|$\)"; then + _notrun "$driver not available" + fi + done +} + # make sure this script returns success true diff --git a/tests/qos-test.c b/tests/qos-test.c index 3c0071b3b7..fd70d73ea5 100644 --- a/tests/qos-test.c +++ b/tests/qos-test.c @@ -18,7 +18,7 @@ #include "qemu/osdep.h" #include <getopt.h> -#include "libqtest.h" +#include "libqtest-single.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qbool.h" #include "qapi/qmp/qstring.h" diff --git a/tests/requirements.txt b/tests/requirements.txt index 3ae0e29ad7..bd1f7590ed 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -2,4 +2,4 @@ # in the tests/venv Python virtual environment. For more info, # refer to: https://pip.pypa.io/en/stable/user_guide/#id1 avocado-framework==68.0 -paramiko +paramiko==2.4.2 diff --git a/tests/rtas-test.c b/tests/rtas-test.c index ee888676ed..167b42db38 100644 --- a/tests/rtas-test.c +++ b/tests/rtas-test.c @@ -14,7 +14,6 @@ static void test_rtas_get_time_of_day(void) time_t t1, t2; qs = qtest_spapr_boot("-machine pseries"); - global_qtest = qs->qts; t1 = time(NULL); ret = qrtas_get_time_of_day(qs->qts, &qs->alloc, &tm, &ns); diff --git a/tests/rtc-test.c b/tests/rtc-test.c index 509be707e3..6309b0ef6c 100644 --- a/tests/rtc-test.c +++ b/tests/rtc-test.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qemu/timer.h" #include "hw/timer/mc146818rtc_regs.h" diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c index d6d0c24909..4506049264 100644 --- a/tests/rtl8139-test.c +++ b/tests/rtl8139-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "libqos/pci-pc.h" #include "qemu/timer.h" #include "qemu-common.h" diff --git a/tests/tcg/.gitignore b/tests/tcg/.gitignore new file mode 100644 index 0000000000..84d7541b28 --- /dev/null +++ b/tests/tcg/.gitignore @@ -0,0 +1,5 @@ +# These are build artefacts which only appear when you are doing +# builds directly in the source tree. +config-*.mak +*-softmmu/ +*-linux-user/ diff --git a/tests/tcg/Makefile.include b/tests/tcg/Makefile.include deleted file mode 100644 index 73b5626fc5..0000000000 --- a/tests/tcg/Makefile.include +++ /dev/null @@ -1,88 +0,0 @@ -# -*- Mode: makefile -*- -# -# TCG tests (per-target rules) -# -# This Makefile fragment is included from the per-target -# Makefile.target so will be invoked for each linux-user program we -# build. We have two options for compiling, either using a configured -# guest compiler or calling one of our docker images to do it for us. -# - -# The per ARCH makefile, if it exists, holds extra information about -# useful docker images or alternative compiler flags. - --include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.include --include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.include - -GUEST_BUILD= -TCG_MAKE=$(SRC_PATH)/tests/tcg/Makefile -# Support installed Cross Compilers - -ifdef CROSS_CC_GUEST - -.PHONY: cross-build-guest-tests -cross-build-guest-tests: - $(call quiet-command, \ - (mkdir -p tests && cd tests && \ - $(MAKE) -f $(TCG_MAKE) CC=$(CROSS_CC_GUEST) \ - BUILD_STATIC=$(CROSS_CC_GUEST_STATIC) \ - EXTRA_CFLAGS=$(CROSS_CC_GUEST_CFLAGS)), \ - "BUILD","$(TARGET_NAME) guest-tests with $(CROSS_CC_GUEST)") - -GUEST_BUILD=cross-build-guest-tests - -endif - -# Support building with Docker - -ifeq ($(HAVE_USER_DOCKER)$(GUEST_BUILD),y) -ifneq ($(DOCKER_IMAGE),) - -# We also need the Docker make rules to depend on -include $(SRC_PATH)/tests/docker/Makefile.include - -DOCKER_COMPILE_CMD="$(DOCKER_SCRIPT) cc --user $(shell id -u) \ - --cc $(DOCKER_CROSS_COMPILER) \ - -i qemu:$(DOCKER_IMAGE) \ - -s $(SRC_PATH) -- " -DOCKER_PREREQ=docker-image-$(DOCKER_IMAGE) - -.PHONY: docker-build-guest-tests -docker-build-guest-tests: $(DOCKER_PREREQ) - $(call quiet-command, \ - (mkdir -p tests && cd tests && \ - $(MAKE) -f $(TCG_MAKE) CC=$(DOCKER_COMPILE_CMD) \ - BUILD_STATIC=y \ - EXTRA_CFLAGS=$(DOCKER_CROSS_COMPILER_CFLAGS)), \ - "BUILD","$(TARGET_NAME) guest-tests with docker qemu:$(DOCKER_IMAGE)") - -GUEST_BUILD=docker-build-guest-tests - -endif -endif - -# Final targets -.PHONY: guest-tests - -ifneq ($(GUEST_BUILD),) -guest-tests: $(GUEST_BUILD) - -run-guest-tests: guest-tests qemu-$(subst y,system-,$(CONFIG_SOFTMMU))$(TARGET_NAME) - $(call quiet-command, \ - (cd tests && $(MAKE) -f $(TCG_MAKE) SPEED=$(SPEED) run), \ - "RUN", "tests for $(TARGET_NAME)") - -else -guest-tests: - $(call quiet-command, /bin/true, "BUILD", \ - "$(TARGET_NAME) guest-tests SKIPPED") - -run-guest-tests: - $(call quiet-command, /bin/true, "RUN", \ - "tests for $(TARGET_NAME) SKIPPED") -endif - -# It doesn't matter if these don't exits -.PHONY: clean-guest-tests -clean-guest-tests: - rm -rf tests || echo "no $(TARGET_NAME) tests to remove" diff --git a/tests/tcg/Makefile.prereqs b/tests/tcg/Makefile.prereqs new file mode 100644 index 0000000000..7494b31b95 --- /dev/null +++ b/tests/tcg/Makefile.prereqs @@ -0,0 +1,18 @@ +# -*- Mode: makefile -*- +# +# TCG Compiler Probe +# +# This Makefile fragment is included multiple times in the main make +# script to probe for available compilers. This is used to build up a +# selection of required docker targets before we invoke a sub-make for +# each target. + +DOCKER_IMAGE:= + +-include $(BUILD_DIR)/tests/tcg/config-$(PROBE_TARGET).mak + +ifneq ($(DOCKER_IMAGE),) +build-tcg-tests-$(PROBE_TARGET): docker-image-$(DOCKER_IMAGE) +$(BUILD_DIR)/tests/tcg/config_$(PROBE_TARGET).mak: config-host.mak +config-host.mak: $(SRC_PATH)/tests/tcg/configure.sh +endif diff --git a/tests/tcg/Makefile.probe b/tests/tcg/Makefile.probe deleted file mode 100644 index 9dc654663d..0000000000 --- a/tests/tcg/Makefile.probe +++ /dev/null @@ -1,31 +0,0 @@ -# -*- Mode: makefile -*- -# -# TCG Compiler Probe -# -# This Makefile fragment is included multiple times in the main make -# script to probe for available compilers. This is used to build up a -# selection of required docker targets before we invoke a sub-make for -# each target. - -# First we need the target makefile which tells us the target architecture --include $(BUILD_DIR)/$(PROBE_TARGET)/config-target.mak - -# Then we load up the target architecture makefiles which tell us -# about the compilers -CROSS_CC_GUEST:= -DOCKER_IMAGE:= -DOCKER_PREREQ:= - --include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.include --include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.include - -ifndef CROSS_CC_GUEST -ifneq ($(DOCKER_IMAGE),) -DOCKER_PREREQ:=docker-image-$(DOCKER_IMAGE) -endif -endif - -# Clean-up -# undefine TARGET_NAME -# undefine TARGET_BASE_ARCH -# undefine TARGET_ABI_DIR diff --git a/tests/tcg/Makefile.qemu b/tests/tcg/Makefile.qemu new file mode 100644 index 0000000000..9c23aeaa2a --- /dev/null +++ b/tests/tcg/Makefile.qemu @@ -0,0 +1,95 @@ +# -*- Mode: makefile -*- +# +# TCG tests (per-target rules) +# +# This Makefile fragment is included from the build-tcg target, once +# for each target we build. We have two options for compiling, either +# using a configured guest compiler or calling one of our docker images +# to do it for us. +# + +include $(SRC_PATH)/rules.mak + +# The configure script fills in extra information about +# useful docker images or alternative compiler flags. + +CROSS_CC_GUEST:= +DOCKER_IMAGE:= +-include $(BUILD_DIR)/tests/tcg/config-$(TARGET).mak + +GUEST_BUILD= +TCG_MAKE=../Makefile.target + +# We also need the Docker make rules to depend on +SKIP_DOCKER_BUILD=1 +include $(SRC_PATH)/tests/docker/Makefile.include + +# Support installed Cross Compilers + +ifdef CROSS_CC_GUEST + +.PHONY: cross-build-guest-tests +cross-build-guest-tests: + $(call quiet-command, \ + (mkdir -p tests/tcg/$(TARGET) && cd tests/tcg/$(TARGET) && \ + $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC="$(CROSS_CC_GUEST)" \ + SRC_PATH="$(SRC_PATH)" BUILD_STATIC=$(CROSS_CC_GUEST_STATIC) \ + EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \ + "BUILD","$(TARGET) guest-tests with $(CROSS_CC_GUEST)") + +GUEST_BUILD=cross-build-guest-tests + +endif + +# Support building with Docker + +ifneq ($(DOCKER_IMAGE),) + +DOCKER_COMPILE_CMD="$(DOCKER_SCRIPT) cc \ + --cc $(DOCKER_CROSS_CC_GUEST) \ + -i qemu:$(DOCKER_IMAGE) \ + -s $(SRC_PATH) -- " + +.PHONY: docker-build-guest-tests +docker-build-guest-tests: docker-image-$(DOCKER_IMAGE) + $(call quiet-command, \ + (mkdir -p tests/tcg/$(TARGET) && cd tests/tcg/$(TARGET) && \ + $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC=$(DOCKER_COMPILE_CMD) \ + SRC_PATH="$(SRC_PATH)" BUILD_STATIC=y \ + EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \ + "BUILD","$(TARGET) guest-tests with docker qemu:$(DOCKER_IMAGE)") + +GUEST_BUILD=docker-build-guest-tests + +endif + +# Final targets +all: + @echo "Do not invoke this Makefile directly"; exit 1 + +.PHONY: guest-tests + +ifneq ($(GUEST_BUILD),) +guest-tests: $(GUEST_BUILD) + +run-guest-tests: guest-tests + $(call quiet-command, \ + (cd tests/tcg/$(TARGET) && \ + $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" \ + SRC_PATH="$(SRC_PATH)" SPEED=$(SPEED) run), \ + "RUN", "tests for $(TARGET_NAME)") + +else +guest-tests: + $(call quiet-command, /bin/true, "BUILD", \ + "$(TARGET) guest-tests SKIPPED") + +run-guest-tests: + $(call quiet-command, /bin/true, "RUN", \ + "tests for $(TARGET) SKIPPED") +endif + +# It doesn't matter if these don't exits +.PHONY: clean-guest-tests +clean-guest-tests: + rm -rf tests/tcg/$(TARGET) diff --git a/tests/tcg/Makefile b/tests/tcg/Makefile.target index 9f56768624..8808beaf74 100644 --- a/tests/tcg/Makefile +++ b/tests/tcg/Makefile.target @@ -29,8 +29,9 @@ # We also expect to be in the tests build dir for the FOO-(linux-user|softmmu). # +all: -include ../../config-host.mak --include ../config-target.mak +-include ../config-$(TARGET).mak # for including , in command strings COMMA := , @@ -62,12 +63,6 @@ CFLAGS= QEMU_CFLAGS= LDFLAGS= -# The QEMU for this TARGET -ifdef CONFIG_USER_ONLY -QEMU=../qemu-$(TARGET_NAME) -else -QEMU=../qemu-system-$(TARGET_NAME) -endif QEMU_OPTS= @@ -82,10 +77,7 @@ ifdef CONFIG_USER_ONLY # The order we include is important. We include multiarch, base arch # and finally arch if it's not the same as base arch. -include $(SRC_PATH)/tests/tcg/multiarch/Makefile.target --include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.target -ifneq ($(TARGET_BASE_ARCH),$(TARGET_NAME)) -include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.target -endif # Add the common build options CFLAGS+=-Wall -O0 -g -fno-strict-aliasing @@ -101,10 +93,7 @@ else # are expected to provide their own build recipes. -include $(SRC_PATH)/tests/tcg/minilib/Makefile.target -include $(SRC_PATH)/tests/tcg/multiarch/system/Makefile.softmmu-target --include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.softmmu-target -ifneq ($(TARGET_BASE_ARCH),$(TARGET_NAME)) -include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.softmmu-target -endif endif diff --git a/tests/tcg/aarch64/Makefile.include b/tests/tcg/aarch64/Makefile.include deleted file mode 100644 index 5d4e4c6f99..0000000000 --- a/tests/tcg/aarch64/Makefile.include +++ /dev/null @@ -1,8 +0,0 @@ -# Makefile.include for AArch64 targets -# -# We don't have any bigendian build tools so we only use this for AArch64 - -ifeq ($(TARGET_NAME),aarch64) -DOCKER_IMAGE=debian-buster-arm64-cross -DOCKER_CROSS_COMPILER=aarch64-linux-gnu-gcc -endif diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target index 2e560e4d08..4c4aaf61dd 100644 --- a/tests/tcg/aarch64/Makefile.softmmu-target +++ b/tests/tcg/aarch64/Makefile.softmmu-target @@ -22,11 +22,11 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc .PRECIOUS: $(CRT_OBJS) %.o: $(CRT_PATH)/%.S - $(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@ + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@ # Build and link the tests %: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) - $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) memory: CFLAGS+=-DCHECK_UNALIGNED=1 diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 31ba9cfcaa..e763dd9da3 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -2,12 +2,14 @@ # # AArch64 specific tweaks +ARM_SRC=$(SRC_PATH)/tests/tcg/arm +VPATH += $(ARM_SRC) + AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64 VPATH += $(AARCH64_SRC) -# we don't build any of the ARM tests -AARCH64_TESTS=$(filter-out $(ARM_TESTS), $(TESTS)) -AARCH64_TESTS+=fcvt +# we don't build any other ARM test +AARCH64_TESTS=fcvt fcvt: LDFLAGS+=-lm @@ -16,6 +18,6 @@ run-fcvt: fcvt $(call diff-out,$<,$(AARCH64_SRC)/fcvt.ref) AARCH64_TESTS += pauth-1 pauth-2 -run-pauth-%: QEMU += -cpu max +run-pauth-%: QEMU_OPTS += -cpu max -TESTS:=$(AARCH64_TESTS) +TESTS += $(AARCH64_TESTS) diff --git a/tests/tcg/alpha/Makefile.include b/tests/tcg/alpha/Makefile.include deleted file mode 100644 index c7dc48eadb..0000000000 --- a/tests/tcg/alpha/Makefile.include +++ /dev/null @@ -1,2 +0,0 @@ -DOCKER_IMAGE=debian-alpha-cross -DOCKER_CROSS_COMPILER=alpha-linux-gnu-gcc diff --git a/tests/tcg/alpha/Makefile.softmmu-target b/tests/tcg/alpha/Makefile.softmmu-target index 3c0f34cc69..09193a62d6 100644 --- a/tests/tcg/alpha/Makefile.softmmu-target +++ b/tests/tcg/alpha/Makefile.softmmu-target @@ -22,11 +22,11 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc .PRECIOUS: $(CRT_OBJS) %.o: $(CRT_PATH)/%.S - $(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@ + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@ # Build and link the tests %: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) - $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) memory: CFLAGS+=-DCHECK_UNALIGNED=0 diff --git a/tests/tcg/arm/Makefile.include b/tests/tcg/arm/Makefile.include deleted file mode 100644 index 8e7eac008f..0000000000 --- a/tests/tcg/arm/Makefile.include +++ /dev/null @@ -1,8 +0,0 @@ -# Makefile.include for all ARM targets -# -# We don't have any bigendian build tools so we only use this for armhf - -ifeq ($(TARGET_NAME),arm) -DOCKER_IMAGE=debian-armhf-cross -DOCKER_CROSS_COMPILER=arm-linux-gnueabihf-gcc -endif diff --git a/tests/tcg/arm/Makefile.softmmu-target b/tests/tcg/arm/Makefile.softmmu-target index 49d48d8a1c..231e9a57b4 100644 --- a/tests/tcg/arm/Makefile.softmmu-target +++ b/tests/tcg/arm/Makefile.softmmu-target @@ -3,8 +3,6 @@ # ARM SoftMMU tests - included from tests/tcg/Makefile # -ifeq ($(TARGET_ABI_DIR),arm) - ARM_SRC=$(SRC_PATH)/tests/tcg/arm # Set search path for all sources @@ -18,12 +16,10 @@ CFLAGS+=-Wl,--build-id=none -x assembler-with-cpp LDFLAGS+=-nostdlib -N -static %: %.S %.ld - $(CC) $(CFLAGS) $(ASFLAGS) $< -o $@ $(LDFLAGS) -T $(ARM_SRC)/$@.ld + $(CC) $(CFLAGS) $(ASFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) -T $(ARM_SRC)/$@.ld # Specific Test Rules test-armv6m-undef: EXTRA_CFLAGS+=-mcpu=cortex-m0 run-test-armv6m-undef: QEMU_OPTS+=-semihosting -M microbit -kernel - -endif diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh new file mode 100755 index 0000000000..6c4a471aea --- /dev/null +++ b/tests/tcg/configure.sh @@ -0,0 +1,234 @@ +#! /bin/sh + +if test -z "$source_path"; then + echo Do not invoke this script directly. It is called + echo automatically by configure. + exit 1 +fi + +write_c_skeleton() { + cat > $TMPC <<EOF +int main(void) { return 0; } +EOF +} + +has() { + command -v "$1" >/dev/null 2>&1 +} + +do_compiler() { + # Run the compiler, capturing its output to the log. First argument + # is compiler binary to execute. + local compiler="$1" + shift + if test -n "$BASH_VERSION"; then eval ' + echo >>config.log " +funcs: ${FUNCNAME[*]} +lines: ${BASH_LINENO[*]}" + '; fi + echo $compiler "$@" >> config.log + $compiler "$@" >> config.log 2>&1 || return $? +} + + +TMPDIR1="config-temp" +TMPC="${TMPDIR1}/qemu-conf.c" +TMPE="${TMPDIR1}/qemu-conf.exe" + +container="no" +if has "docker" || has "podman"; then + container=$($python $source_path/tests/docker/docker.py probe) +fi + +# cross compilers defaults, can be overridden with --cross-cc-ARCH +: ${cross_cc_aarch64="aarch64-linux-gnu-gcc"} +: ${cross_cc_aarch64_be="$cross_cc_aarch64"} +: ${cross_cc_cflags_aarch64_be="-mbig-endian"} +: ${cross_cc_arm="arm-linux-gnueabihf-gcc"} +: ${cross_cc_cflags_armeb="-mbig-endian"} +: ${cross_cc_i386="i386-pc-linux-gnu-gcc"} +: ${cross_cc_cflags_i386="-m32"} +: ${cross_cc_x86_64="x86_64-pc-linux-gnu-gcc"} +: ${cross_cc_cflags_x86_64="-m64"} +: ${cross_cc_ppc="powerpc-linux-gnu-gcc"} +: ${cross_cc_cflags_ppc="-m32"} +: ${cross_cc_ppc64="powerpc-linux-gnu-gcc"} +: ${cross_cc_cflags_ppc64="-m64"} +: ${cross_cc_ppc64le="powerpc64le-linux-gnu-gcc"} +: ${cross_cc_cflags_s390x="-m64"} +: ${cross_cc_cflags_sparc="-m32 -mv8plus -mcpu=ultrasparc"} +: ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"} + +for target in $target_list; do + arch=${target%%-*} + case $arch in + arm|armeb) + arches=arm + ;; + aarch64|aarch64_be) + arches="aarch64 arm" + ;; + mips*) + arches=mips + ;; + ppc*) + arches=ppc + ;; + sh4|sh4eb) + arches=sh4 + ;; + x86_64) + arches="x86_64 i386" + ;; + xtensa|xtensaeb) + arches=xtensa + ;; + alpha|cris|hppa|i386|lm32|m68k|openrisc|riscv64|s390x|sh4|sparc64) + arches=$target + ;; + *) + continue + ;; + esac + + container_image= + case $target in + aarch64-*) + # We don't have any bigendian build tools so we only use this for AArch64 + container_image=debian-arm64-cross + container_cross_cc=aarch64-linux-gnu-gcc + ;; + alpha-*) + container_image=debian-alpha-cross + container_cross_cc=alpha-linux-gnu-gcc + ;; + arm-*) + # We don't have any bigendian build tools so we only use this for ARM + container_image=debian-armhf-cross + container_cross_cc=arm-linux-gnueabihf-gcc + ;; + cris-*) + container_image=fedora-cris-cross + container_cross_cc=cris-linux-gnu-gcc + ;; + hppa-*) + container_image=debian-hppa-cross + container_cross_cc=hppa-linux-gnu-gcc + ;; + i386-*) + container_image=fedora-i386-cross + container_cross_cc=gcc + ;; + m68k-*) + container_image=debian-m68k-cross + container_cross_cc=m68k-linux-gnu-gcc + ;; + mips64el-*) + container_image=debian-mips64el-cross + container_cross_cc=mips64el-linux-gnuabi64-gcc + ;; + mips64-*) + container_image=debian-mips64-cross + container_cross_cc=mips64-linux-gnuabi64-gcc + ;; + mipsel-*) + container_image=debian-mipsel-cross + container_cross_cc=mipsel-linux-gnu-gcc + ;; + mips-*) + container_image=debian-mips-cross + container_cross_cc=mips-linux-gnu-gcc + ;; + ppc-*|ppc64abi32-*) + container_image=debian-powerpc-cross + container_cross_cc=powerpc-linux-gnu-gcc + ;; + ppc64-*) + container_image=debian-ppc64-cross + container_cross_cc=powerpc64-linux-gnu-gcc + ;; + ppc64le-*) + container_image=debian-ppc64el-cross + container_cross_cc=powerpc64le-linux-gnu-gcc + ;; + riscv64-*) + container_image=debian-riscv64-cross + container_cross_cc=riscv64-linux-gnu-gcc + ;; + s390x-*) + container_image=debian-s390x-cross + container_cross_cc=s390x-linux-gnu-gcc + ;; + sh4-*) + container_image=debian-sh4-cross + container_cross_cc=sh4-linux-gnu-gcc + ;; + sparc64-*) + container_image=debian-sparc64-cross + container_cross_cc=sparc64-linux-gnu-gcc + ;; + xtensa*-softmmu) + container_image=debian-xtensa-cross + + # default to the dc232b cpu + container_cross_cc=/opt/2018.02/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-gcc + ;; + esac + + config_target_mak=tests/tcg/config-$target.mak + + echo "# Automatically generated by configure - do not modify" > $config_target_mak + echo "TARGET_NAME=$arch" >> $config_target_mak + case $target in + *-linux-user | *-bsd-user) + echo "CONFIG_USER_ONLY=y" >> $config_target_mak + echo "QEMU=\$(BUILD_DIR)/$target/qemu-$arch" >> $config_target_mak + ;; + *-softmmu) + echo "CONFIG_SOFTMMU=y" >> $config_target_mak + echo "QEMU=\$(BUILD_DIR)/$target/qemu-system-$arch" >> $config_target_mak + ;; + esac + + eval "target_compiler_cflags=\${cross_cc_cflags_$arch}" + echo "CROSS_CC_GUEST_CFLAGS=$target_compiler_cflags" >> $config_target_mak + + got_cross_cc=no + for i in $arch $arches; do + if eval test "x\${cross_cc_$i+yes}" != xyes; then + continue + fi + + eval "target_compiler=\${cross_cc_$i}" + if ! has $target_compiler; then + continue + fi + write_c_skeleton + if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC -static ; then + # For host systems we might get away with building without -static + if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC ; then + continue + fi + echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak + else + echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak + fi + echo "CROSS_CC_GUEST=$target_compiler" >> $config_target_mak + enabled_cross_compilers="$enabled_cross_compilers $target_compiler" + got_cross_cc=yes + break + done + + if test $got_cross_cc = no && test "$container" != no && test -n "$container_image"; then + echo "DOCKER_IMAGE=$container_image" >> $config_target_mak + echo "DOCKER_CROSS_CC_GUEST=$container_cross_cc" >> $config_target_mak + fi +done + +# report container support state +echo "cross containers $container" + +if test -n "$enabled_cross_compilers"; then + echo + echo "NOTE: guest cross-compilers enabled:$enabled_cross_compilers" +fi diff --git a/tests/tcg/cris/Makefile.include b/tests/tcg/cris/Makefile.include deleted file mode 100644 index 1c037824bf..0000000000 --- a/tests/tcg/cris/Makefile.include +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile.include for all CRIS targets -# - -DOCKER_IMAGE=fedora-cris-cross -DOCKER_CROSS_COMPILER=cris-linux-gnu-gcc diff --git a/tests/tcg/hppa/Makefile.include b/tests/tcg/hppa/Makefile.include deleted file mode 100644 index da2353430e..0000000000 --- a/tests/tcg/hppa/Makefile.include +++ /dev/null @@ -1,2 +0,0 @@ -DOCKER_IMAGE=debian-hppa-cross -DOCKER_CROSS_COMPILER=hppa-linux-gnu-gcc diff --git a/tests/tcg/i386/Makefile.include b/tests/tcg/i386/Makefile.include deleted file mode 100644 index be1c3008dd..0000000000 --- a/tests/tcg/i386/Makefile.include +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile.include for all i386 -# -# There is enough brokeness in x86_64 compilers that we don't default -# to using the x86_64 system compiler for i386 binaries. -# - -DOCKER_IMAGE=fedora-i386-cross -DOCKER_CROSS_COMPILER=gcc diff --git a/tests/tcg/i386/Makefile.softmmu-target b/tests/tcg/i386/Makefile.softmmu-target index 0a4364868c..1c8790eecd 100644 --- a/tests/tcg/i386/Makefile.softmmu-target +++ b/tests/tcg/i386/Makefile.softmmu-target @@ -12,17 +12,9 @@ X64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/x86_64/system # These objects provide the basic boot code and helper functions for all tests CRT_OBJS=boot.o -ifeq ($(TARGET_X86_64), y) -CRT_PATH=$(X64_SYSTEM_SRC) -CFLAGS=-march=x86-64 -LINK_SCRIPT=$(X64_SYSTEM_SRC)/kernel.ld -LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_x86_64 -else CRT_PATH=$(I386_SYSTEM_SRC) -CFLAGS+=-m32 LINK_SCRIPT=$(I386_SYSTEM_SRC)/kernel.ld LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_i386 -endif CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC) LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc @@ -32,11 +24,11 @@ TESTS+=$(MULTIARCH_TESTS) .PRECIOUS: $(CRT_OBJS) %.o: $(CRT_PATH)/%.S - $(CC) $(CFLAGS) -c $< -o $@ + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@ # Build and link the tests %: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) - $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) memory: CFLAGS+=-DCHECK_UNALIGNED=1 diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index d0eb7023e5..08c5736a4d 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -6,14 +6,11 @@ I386_SRC=$(SRC_PATH)/tests/tcg/i386 VPATH += $(I386_SRC) I386_SRCS=$(notdir $(wildcard $(I386_SRC)/*.c)) -I386_TESTS=$(I386_SRCS:.c=) -I386_ONLY_TESTS=$(filter-out test-i386-ssse3, $(I386_TESTS)) +ALL_X86_TESTS=$(I386_SRCS:.c=) +I386_TESTS:=$(filter-out test-i386-ssse3, $(ALL_X86_TESTS)) +X86_64_TESTS:=$(filter test-i386-ssse3, $(ALL_X86_TESTS)) # Update TESTS -TESTS+=$(I386_ONLY_TESTS) - -ifneq ($(TARGET_NAME),x86_64) -CFLAGS+=-m32 -endif +TESTS=$(MULTIARCH_TESTS) $(I386_TESTS) # # hello-i386 is a barebones app @@ -26,7 +23,7 @@ hello-i386: LDFLAGS+=-nostdlib # test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ \ + $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ \ $(<D)/test-i386.c $(<D)/test-i386-code16.S $(<D)/test-i386-vm86.S -lm ifeq ($(SPEED), slow) diff --git a/tests/tcg/m68k/Makefile.include b/tests/tcg/m68k/Makefile.include deleted file mode 100644 index cd7c6bf50d..0000000000 --- a/tests/tcg/m68k/Makefile.include +++ /dev/null @@ -1,2 +0,0 @@ -DOCKER_IMAGE=debian-m68k-cross -DOCKER_CROSS_COMPILER=m68k-linux-gnu-gcc diff --git a/tests/tcg/minilib/Makefile.target b/tests/tcg/minilib/Makefile.target index 3ed8077d0f..c821d2806a 100644 --- a/tests/tcg/minilib/Makefile.target +++ b/tests/tcg/minilib/Makefile.target @@ -18,4 +18,4 @@ MINILIB_INC=-isystem $(SYSTEM_MINILIB_SRC) .PRECIOUS: $(MINILIB_OBJS) %.o: $(SYSTEM_MINILIB_SRC)/%.c - $(CC) $(CFLAGS) -c $< -o $@ + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@ diff --git a/tests/tcg/mips/Makefile.include b/tests/tcg/mips/Makefile.include deleted file mode 100644 index 4a14fc078d..0000000000 --- a/tests/tcg/mips/Makefile.include +++ /dev/null @@ -1,20 +0,0 @@ -# -# Makefile.include for all MIPs targets -# -# As Debian doesn't support mip64 in big endian mode the only way to -# build BE is to pass a working cross compiler to ./configure -# - -ifeq ($(TARGET_NAME),mips64el) -DOCKER_IMAGE=debian-mips64el-cross -DOCKER_CROSS_COMPILER=mips64el-linux-gnuabi64-gcc -else ifeq ($(TARGET_NAME),mips64) -DOCKER_IMAGE=debian-mips64-cross -DOCKER_CROSS_COMPILER=mips64-linux-gnuabi64-gcc -else ifeq ($(TARGET_NAME),mipsel) -DOCKER_IMAGE=debian-mipsel-cross -DOCKER_CROSS_COMPILER=mipsel-linux-gnu-gcc -else ifeq ($(TARGET_NAME),mips) -DOCKER_IMAGE=debian-mips-cross -DOCKER_CROSS_COMPILER=mips-linux-gnu-gcc -endif diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index b77084c146..6b1e30e2fe 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -12,8 +12,13 @@ VPATH += $(MULTIARCH_SRC) MULTIARCH_SRCS =$(notdir $(wildcard $(MULTIARCH_SRC)/*.c)) MULTIARCH_TESTS =$(MULTIARCH_SRCS:.c=) +# FIXME: ppc64abi32 linux-test seems to have issues but the other basic tests work +ifeq ($(TARGET_NAME),ppc64abi32) +BROKEN_TESTS = linux-test +endif + # Update TESTS -TESTS +=$(MULTIARCH_TESTS) +TESTS += $(filter-out $(BROKEN_TESTS), $(MULTIARCH_TESTS)) # # The following are any additional rules needed to build things diff --git a/tests/tcg/ppc/Makefile.include b/tests/tcg/ppc/Makefile.include deleted file mode 100644 index ae01fb8fad..0000000000 --- a/tests/tcg/ppc/Makefile.include +++ /dev/null @@ -1,10 +0,0 @@ -ifeq ($(TARGET_NAME),ppc) -DOCKER_IMAGE=debian-powerpc-cross -DOCKER_CROSS_COMPILER=powerpc-linux-gnu-gcc -else ifeq ($(TARGET_NAME),ppc64) -DOCKER_IMAGE=debian-ppc64-cross -DOCKER_CROSS_COMPILER=powerpc64-linux-gnu-gcc -else ifeq ($(TARGET_NAME),ppc64le) -DOCKER_IMAGE=debian-ppc64el-cross -DOCKER_CROSS_COMPILER=powerpc64le-linux-gnu-gcc -endif diff --git a/tests/tcg/riscv/Makefile.include b/tests/tcg/riscv/Makefile.include deleted file mode 100644 index d92ac6c89f..0000000000 --- a/tests/tcg/riscv/Makefile.include +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile.include for all RISCV targets -# -# Debian only really cares about 64 bit going forward -# - -ifeq ($(TARGET_NAME),riscv64) -DOCKER_IMAGE=debian-riscv64-cross -DOCKER_CROSS_COMPILER=riscv64-linux-gnu-gcc -endif diff --git a/tests/tcg/s390x/Makefile.include b/tests/tcg/s390x/Makefile.include deleted file mode 100644 index 1f58115d96..0000000000 --- a/tests/tcg/s390x/Makefile.include +++ /dev/null @@ -1,2 +0,0 @@ -DOCKER_IMAGE=debian-s390x-cross -DOCKER_CROSS_COMPILER=s390x-linux-gnu-gcc diff --git a/tests/tcg/sh4/Makefile.include b/tests/tcg/sh4/Makefile.include deleted file mode 100644 index ad21594d9d..0000000000 --- a/tests/tcg/sh4/Makefile.include +++ /dev/null @@ -1,4 +0,0 @@ -ifneq ($(TARGET_NAME), sh4eb) -DOCKER_IMAGE=debian-sh4-cross -DOCKER_CROSS_COMPILER=sh4-linux-gnu-gcc -endif diff --git a/tests/tcg/sparc64/Makefile.include b/tests/tcg/sparc64/Makefile.include deleted file mode 100644 index 95fc8dee9f..0000000000 --- a/tests/tcg/sparc64/Makefile.include +++ /dev/null @@ -1,2 +0,0 @@ -DOCKER_IMAGE=debian-sparc64-cross -DOCKER_CROSS_COMPILER=sparc64-linux-gnu-gcc diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Makefile.softmmu-target new file mode 100644 index 0000000000..df252e761c --- /dev/null +++ b/tests/tcg/x86_64/Makefile.softmmu-target @@ -0,0 +1,36 @@ +# +# x86 system tests +# +# This currently builds only for i386. The common C code is built +# with standard compiler flags however so we can support both by +# adding additional boot files for x86_64. +# + +I386_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/i386/system +X64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/x86_64/system + +# These objects provide the basic boot code and helper functions for all tests +CRT_OBJS=boot.o + +CRT_PATH=$(X64_SYSTEM_SRC) +LINK_SCRIPT=$(X64_SYSTEM_SRC)/kernel.ld +LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_x86_64 +CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC) +LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc + +TESTS+=$(MULTIARCH_TESTS) + +# building head blobs +.PRECIOUS: $(CRT_OBJS) + +%.o: $(CRT_PATH)/%.S + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@ + +# Build and link the tests +%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) + +memory: CFLAGS+=-DCHECK_UNALIGNED=1 + +# Running +QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target index 74f170b9ed..20bf96202a 100644 --- a/tests/tcg/x86_64/Makefile.target +++ b/tests/tcg/x86_64/Makefile.target @@ -6,9 +6,10 @@ # $(SRC)/tests/tcg/i386/ # -X86_64_TESTS=$(filter-out $(I386_ONLY_TESTS), $(TESTS)) -X86_64_TESTS+=test-x86_64 -TESTS:=$(X86_64_TESTS) +include $(SRC_PATH)/tests/tcg/i386/Makefile.target + +TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64 +QEMU_OPTS += -cpu max test-x86_64: LDFLAGS+=-lm -lc test-x86_64: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h diff --git a/tests/tcg/xtensa/Makefile.include b/tests/tcg/xtensa/Makefile.include deleted file mode 100644 index 423c00a5d3..0000000000 --- a/tests/tcg/xtensa/Makefile.include +++ /dev/null @@ -1,11 +0,0 @@ -# Makefile.include for xtensa targets -# -# The compilers can only be used for building system tests - -ifeq ($(CONFIG_SOFTMMU),y) -DOCKER_IMAGE=debian-xtensa-cross - -# default to the dc232b cpu -DOCKER_CROSS_COMPILER=/opt/2018.02/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-gcc -DOCKER_CROSS_LINKER=/opt/2018.02/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-ld -endif diff --git a/tests/tcg/xtensa/Makefile.softmmu-target b/tests/tcg/xtensa/Makefile.softmmu-target index 8212d96b81..9530cac2ad 100644 --- a/tests/tcg/xtensa/Makefile.softmmu-target +++ b/tests/tcg/xtensa/Makefile.softmmu-target @@ -34,9 +34,9 @@ $(XTENSA_USABLE_TESTS): linker.ld macros.inc $(CRT) Makefile.softmmu-target # special rule for common blobs %.o: %.S - $(CC) $(XTENSA_INC) $($*_ASFLAGS) $(ASFLAGS) -c $< -o $@ + $(CC) $(XTENSA_INC) $($*_ASFLAGS) $(ASFLAGS) $(EXTRA_CFLAGS) -c $< -o $@ %: %.S - $(CC) $(XTENSA_INC) $(ASFLAGS) $< -o $@ $(LDFLAGS) $(NOSTDFLAGS) $(CRT) + $(CC) $(XTENSA_INC) $(ASFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) $(NOSTDFLAGS) $(CRT) endif diff --git a/tests/test-arm-mptimer.c b/tests/test-arm-mptimer.c index 156a39f50d..7a56d56da9 100644 --- a/tests/test-arm-mptimer.c +++ b/tests/test-arm-mptimer.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "qemu/timer.h" -#include "libqtest.h" +#include "libqtest-single.h" #define TIMER_BLOCK_SCALE(s) ((((s) & 0xff) + 1) * 10) diff --git a/tests/test-char.c b/tests/test-char.c index b56e43c1eb..f3ebdffd87 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -667,7 +667,7 @@ char_socket_addr_to_opt_str(SocketAddress *addr, bool fd_pass, char *optstr; g_assert(!reconnect); if (is_listen) { - qio_channel_socket_listen_sync(ioc, addr, &error_abort); + qio_channel_socket_listen_sync(ioc, addr, 1, &error_abort); } else { qio_channel_socket_connect_sync(ioc, addr, &error_abort); } @@ -892,7 +892,7 @@ static void char_socket_client_test(gconstpointer opaque) */ ioc = qio_channel_socket_new(); g_assert_nonnull(ioc); - qio_channel_socket_listen_sync(ioc, config->addr, &error_abort); + qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort); addr = qio_channel_socket_get_local_address(ioc, &error_abort); g_assert_nonnull(addr); diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c index d172f3070f..d43083a766 100644 --- a/tests/test-io-channel-socket.c +++ b/tests/test-io-channel-socket.c @@ -57,7 +57,7 @@ static void test_io_channel_setup_sync(SocketAddress *listen_addr, QIOChannelSocket *lioc; lioc = qio_channel_socket_new(); - qio_channel_socket_listen_sync(lioc, listen_addr, &error_abort); + qio_channel_socket_listen_sync(lioc, listen_addr, 1, &error_abort); if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) { SocketAddress *laddr = qio_channel_socket_get_local_address( @@ -113,7 +113,7 @@ static void test_io_channel_setup_async(SocketAddress *listen_addr, lioc = qio_channel_socket_new(); qio_channel_socket_listen_async( - lioc, listen_addr, + lioc, listen_addr, 1, test_io_channel_complete, &data, NULL, NULL); g_main_loop_run(data.loop); diff --git a/tests/test-netfilter.c b/tests/test-netfilter.c index e47075dd06..22927ee6ab 100644 --- a/tests/test-netfilter.c +++ b/tests/test-netfilter.c @@ -9,7 +9,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qapi/qmp/qdict.h" /* add a netfilter to a netdev and then remove it */ diff --git a/tests/test-util-filemonitor.c b/tests/test-util-filemonitor.c index 46e781c022..301cd2db61 100644 --- a/tests/test-util-filemonitor.c +++ b/tests/test-util-filemonitor.c @@ -45,6 +45,11 @@ typedef struct { const char *filedst; int64_t *watchid; int eventid; + /* + * Only valid with OP_EVENT - this event might be + * swapped with the next OP_EVENT + */ + bool swapnext; } QFileMonitorTestOp; typedef struct { @@ -98,6 +103,10 @@ qemu_file_monitor_test_handler(int64_t id, QFileMonitorTestData *data = opaque; QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1); + if (debug) { + g_printerr("Queue event id %" PRIx64 " event %d file %s\n", + id, event, filename); + } rec->id = id; rec->event = event; rec->filename = g_strdup(filename); @@ -125,7 +134,8 @@ qemu_file_monitor_test_record_free(QFileMonitorTestRecord *rec) * to wait for the event to be queued for us. */ static QFileMonitorTestRecord * -qemu_file_monitor_test_next_record(QFileMonitorTestData *data) +qemu_file_monitor_test_next_record(QFileMonitorTestData *data, + QFileMonitorTestRecord *pushback) { GTimer *timer = g_timer_new(); QFileMonitorTestRecord *record = NULL; @@ -139,9 +149,15 @@ qemu_file_monitor_test_next_record(QFileMonitorTestData *data) } if (data->records) { record = data->records->data; - tmp = data->records; - data->records = g_list_remove_link(data->records, tmp); - g_list_free(tmp); + if (pushback) { + data->records->data = pushback; + } else { + tmp = data->records; + data->records = g_list_remove_link(data->records, tmp); + g_list_free(tmp); + } + } else if (pushback) { + qemu_file_monitor_test_record_free(pushback); } qemu_mutex_unlock(&data->lock); @@ -158,13 +174,15 @@ static bool qemu_file_monitor_test_expect(QFileMonitorTestData *data, int64_t id, QFileMonitorEvent event, - const char *filename) + const char *filename, + bool swapnext) { QFileMonitorTestRecord *rec; bool ret = false; - rec = qemu_file_monitor_test_next_record(data); + rec = qemu_file_monitor_test_next_record(data, NULL); + retry: if (!rec) { g_printerr("Missing event watch id %" PRIx64 " event %d file %s\n", id, event, filename); @@ -172,6 +190,11 @@ qemu_file_monitor_test_expect(QFileMonitorTestData *data, } if (id != rec->id) { + if (swapnext) { + rec = qemu_file_monitor_test_next_record(data, rec); + swapnext = false; + goto retry; + } g_printerr("Expected watch id %" PRIx64 " but got %" PRIx64 "\n", id, rec->id); goto cleanup; @@ -347,7 +370,8 @@ test_file_monitor_events(void) .filesrc = "fish", }, { .type = QFILE_MONITOR_TEST_OP_EVENT, .filesrc = "", .watchid = &watch4, - .eventid = QFILE_MONITOR_EVENT_IGNORED }, + .eventid = QFILE_MONITOR_EVENT_IGNORED, + .swapnext = true }, { .type = QFILE_MONITOR_TEST_OP_EVENT, .filesrc = "fish", .watchid = &watch0, .eventid = QFILE_MONITOR_EVENT_DELETED }, @@ -493,8 +517,9 @@ test_file_monitor_events(void) g_printerr("Event id=%" PRIx64 " event=%d file=%s\n", *op->watchid, op->eventid, op->filesrc); } - if (!qemu_file_monitor_test_expect( - &data, *op->watchid, op->eventid, op->filesrc)) + if (!qemu_file_monitor_test_expect(&data, *op->watchid, + op->eventid, op->filesrc, + op->swapnext)) goto cleanup; break; case QFILE_MONITOR_TEST_OP_CREATE: diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c index e2a3a8a093..8ce55efe70 100644 --- a/tests/test-util-sockets.c +++ b/tests/test-util-sockets.c @@ -93,7 +93,7 @@ static void test_socket_fd_pass_name_good(void) g_assert_cmpint(fd, !=, mon_fd); close(fd); - fd = socket_listen(&addr, &error_abort); + fd = socket_listen(&addr, 1, &error_abort); g_assert_cmpint(fd, !=, -1); g_assert_cmpint(fd, !=, mon_fd); close(fd); @@ -124,7 +124,7 @@ static void test_socket_fd_pass_name_bad(void) g_assert_cmpint(fd, ==, -1); error_free_or_abort(&err); - fd = socket_listen(&addr, &err); + fd = socket_listen(&addr, 1, &err); g_assert_cmpint(fd, ==, -1); error_free_or_abort(&err); @@ -151,7 +151,7 @@ static void test_socket_fd_pass_name_nomon(void) g_assert_cmpint(fd, ==, -1); error_free_or_abort(&err); - fd = socket_listen(&addr, &err); + fd = socket_listen(&addr, 1, &err); g_assert_cmpint(fd, ==, -1); error_free_or_abort(&err); @@ -174,7 +174,7 @@ static void test_socket_fd_pass_num_good(void) fd = socket_connect(&addr, &error_abort); g_assert_cmpint(fd, ==, sfd); - fd = socket_listen(&addr, &error_abort); + fd = socket_listen(&addr, 1, &error_abort); g_assert_cmpint(fd, ==, sfd); g_free(addr.u.fd.str); @@ -197,7 +197,7 @@ static void test_socket_fd_pass_num_bad(void) g_assert_cmpint(fd, ==, -1); error_free_or_abort(&err); - fd = socket_listen(&addr, &err); + fd = socket_listen(&addr, 1, &err); g_assert_cmpint(fd, ==, -1); error_free_or_abort(&err); @@ -220,7 +220,7 @@ static void test_socket_fd_pass_num_nocli(void) g_assert_cmpint(fd, ==, -1); error_free_or_abort(&err); - fd = socket_listen(&addr, &err); + fd = socket_listen(&addr, 1, &err); g_assert_cmpint(fd, ==, -1); error_free_or_abort(&err); diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c index e75b959950..772287bdb4 100644 --- a/tests/test-x86-cpuid-compat.c +++ b/tests/test-x86-cpuid-compat.c @@ -4,7 +4,7 @@ #include "qapi/qmp/qlist.h" #include "qapi/qmp/qnum.h" #include "qapi/qmp/qbool.h" -#include "libqtest.h" +#include "libqtest-single.h" static char *get_cpu0_qom_path(void) { diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c index f599309a4a..f930a96b83 100644 --- a/tests/tmp105-test.c +++ b/tests/tmp105-test.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "libqos/qgraph.h" #include "libqos/i2c.h" #include "qapi/qmp/qdict.h" diff --git a/tests/tpm-crb-test.c b/tests/tpm-crb-test.c index a139caa51d..632fb7fbd8 100644 --- a/tests/tpm-crb-test.c +++ b/tests/tpm-crb-test.c @@ -15,7 +15,7 @@ #include "hw/acpi/tpm.h" #include "io/channel-socket.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qemu/module.h" #include "tpm-emu.h" diff --git a/tests/tpm-emu.c b/tests/tpm-emu.c index 125e697181..c43ac4aef8 100644 --- a/tests/tpm-emu.c +++ b/tests/tpm-emu.c @@ -76,7 +76,7 @@ void *tpm_emu_ctrl_thread(void *data) QIOChannelSocket *lioc = qio_channel_socket_new(); QIOChannel *ioc; - qio_channel_socket_listen_sync(lioc, s->addr, &error_abort); + qio_channel_socket_listen_sync(lioc, s->addr, 1, &error_abort); g_mutex_lock(&s->data_mutex); s->data_cond_signal = true; diff --git a/tests/tpm-tests.c b/tests/tpm-tests.c index e640777aa9..6e45a0ba85 100644 --- a/tests/tpm-tests.c +++ b/tests/tpm-tests.c @@ -15,7 +15,7 @@ #include "qemu/osdep.h" #include <glib/gstdio.h> -#include "libqtest.h" +#include "libqtest-single.h" #include "tpm-tests.h" static bool diff --git a/tests/tpm-tis-test.c b/tests/tpm-tis-test.c index 92a7e95aad..dcf30e05b7 100644 --- a/tests/tpm-tis-test.c +++ b/tests/tpm-tis-test.c @@ -17,7 +17,7 @@ #include "hw/acpi/tpm.h" #include "io/channel-socket.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qemu/module.h" #include "tpm-emu.h" diff --git a/tests/usb-hcd-ohci-test.c b/tests/usb-hcd-ohci-test.c index 0cd73b7363..19d760f3fb 100644 --- a/tests/usb-hcd-ohci-test.c +++ b/tests/usb-hcd-ohci-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qemu/module.h" #include "libqos/usb.h" #include "libqos/qgraph.h" diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c index 2eef8e3d1c..7a117b64d9 100644 --- a/tests/usb-hcd-uhci-test.c +++ b/tests/usb-hcd-uhci-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "libqos/libqos.h" #include "libqos/usb.h" #include "libqos/libqos-pc.h" diff --git a/tests/usb-hcd-xhci-test.c b/tests/usb-hcd-xhci-test.c index 01845371f9..10ef9d2a91 100644 --- a/tests/usb-hcd-xhci-test.c +++ b/tests/usb-hcd-xhci-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "libqos/usb.h" diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index 6ae8a23688..91ea373ba5 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "qemu/config-file.h" diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 30e6cf3e63..e7b58e3a0c 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qemu/module.h" #include "hw/9pfs/9p.h" #include "hw/9pfs/9p-synth.h" diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 982ff1538c..ed13167392 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -9,7 +9,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qemu/bswap.h" #include "qemu/module.h" #include "standard-headers/linux/virtio_blk.h" @@ -737,6 +737,7 @@ static void resize(void *obj, void *data, QGuestAllocator *t_alloc) int n_size = TEST_IMAGE_SIZE / 2; uint64_t capacity; QVirtQueue *vq; + QTestState *qts = global_qtest; vq = qvirtqueue_setup(dev, t_alloc, 0); @@ -746,7 +747,7 @@ static void resize(void *obj, void *data, QGuestAllocator *t_alloc) " 'arguments': { 'device': 'drive0', " " 'size': %d } }", n_size); - qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US); + qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US); capacity = qvirtio_config_readq(dev, 0); g_assert_cmpint(capacity, ==, n_size / 512); diff --git a/tests/virtio-ccw-test.c b/tests/virtio-ccw-test.c index 9f445ef4ad..d05236407b 100644 --- a/tests/virtio-ccw-test.c +++ b/tests/virtio-ccw-test.c @@ -14,7 +14,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "libqos/virtio.h" static void virtio_balloon_nop(void) diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c index 840875aaae..a08e2ffe12 100644 --- a/tests/virtio-net-test.c +++ b/tests/virtio-net-test.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qemu/iov.h" #include "qemu/module.h" #include "qapi/qmp/qdict.h" diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c index 09348765d7..7c8f9b27f8 100644 --- a/tests/virtio-scsi-test.c +++ b/tests/virtio-scsi-test.c @@ -9,7 +9,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qemu/module.h" #include "scsi/constants.h" #include "libqos/libqos-pc.h" diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c index e584ad76e8..2541034822 100644 --- a/tests/virtio-serial-test.c +++ b/tests/virtio-serial-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "qemu/module.h" #include "libqos/virtio-serial.h" diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index 3560716092..fea348e845 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -80,6 +80,7 @@ vm-boot-serial-%: $(IMAGES_DIR)/%.img vm-boot-ssh-%: $(IMAGES_DIR)/%.img $(call quiet-command, \ $(SRC_PATH)/tests/vm/$* \ + $(if $(J),--jobs $(J)) \ --image "$<" \ --interactive \ false, \ diff --git a/tests/vm/fedora b/tests/vm/fedora index e8fa5bf0d2..7fec1479fb 100755 --- a/tests/vm/fedora +++ b/tests/vm/fedora @@ -23,7 +23,7 @@ class FedoraVM(basevm.BaseVM): name = "fedora" arch = "x86_64" - base = "http://dl.fedoraproject.org/pub/fedora/linux/releases/30/" + base = "https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/30/" link = base + "Server/x86_64/iso/Fedora-Server-netinst-x86_64-30-1.2.iso" repo = base + "Server/x86_64/os/" full = base + "Everything/x86_64/os/" diff --git a/trace/mem-internal.h b/trace/mem-internal.h index f6efaf6d6b..3444fbc596 100644 --- a/trace/mem-internal.h +++ b/trace/mem-internal.h @@ -16,7 +16,7 @@ #define TRACE_MEM_ST (1ULL << 5) /* store (y/n) */ static inline uint8_t trace_mem_build_info( - int size_shift, bool sign_extend, TCGMemOp endianness, bool store) + int size_shift, bool sign_extend, MemOp endianness, bool store) { uint8_t res; @@ -33,7 +33,7 @@ static inline uint8_t trace_mem_build_info( return res; } -static inline uint8_t trace_mem_get_info(TCGMemOp op, bool store) +static inline uint8_t trace_mem_get_info(MemOp op, bool store) { return trace_mem_build_info(op & MO_SIZE, !!(op & MO_SIGN), op & MO_BSWAP, store); diff --git a/trace/mem.h b/trace/mem.h index 2b58196e53..8cf213d85b 100644 --- a/trace/mem.h +++ b/trace/mem.h @@ -18,7 +18,7 @@ * * Return a value for the 'info' argument in guest memory access traces. */ -static uint8_t trace_mem_get_info(TCGMemOp op, bool store); +static uint8_t trace_mem_get_info(MemOp op, bool store); /** * trace_mem_build_info: @@ -26,7 +26,7 @@ static uint8_t trace_mem_get_info(TCGMemOp op, bool store); * Return a value for the 'info' argument in guest memory access traces. */ static uint8_t trace_mem_build_info(int size_shift, bool sign_extend, - TCGMemOp endianness, bool store); + MemOp endianness, bool store); #include "trace/mem-internal.h" @@ -3765,7 +3765,7 @@ static int vnc_display_listen(VncDisplay *vd, qio_net_listener_set_name(vd->listener, "vnc-listen"); for (i = 0; i < nsaddr; i++) { if (qio_net_listener_open_sync(vd->listener, - saddr[i], + saddr[i], 1, errp) < 0) { return -1; } @@ -3780,7 +3780,7 @@ static int vnc_display_listen(VncDisplay *vd, qio_net_listener_set_name(vd->wslistener, "vnc-ws-listen"); for (i = 0; i < nwsaddr; i++) { if (qio_net_listener_open_sync(vd->wslistener, - wsaddr[i], + wsaddr[i], 1, errp) < 0) { return -1; } diff --git a/util/memfd.c b/util/memfd.c index 00334e5b21..4a3c07e0be 100644 --- a/util/memfd.c +++ b/util/memfd.c @@ -35,7 +35,7 @@ #include <sys/syscall.h> #include <asm/unistd.h> -static int memfd_create(const char *name, unsigned int flags) +int memfd_create(const char *name, unsigned int flags) { #ifdef __NR_memfd_create return syscall(__NR_memfd_create, name, flags); diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index e3a1666578..98ff3a1cce 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -31,6 +31,7 @@ #include "qapi/qobject-input-visitor.h" #include "qapi/qobject-output-visitor.h" #include "qemu/cutils.h" +#include "trace.h" #ifndef AI_ADDRCONFIG # define AI_ADDRCONFIG 0 @@ -207,6 +208,7 @@ static int try_bind(int socket, InetSocketAddress *saddr, struct addrinfo *e) static int inet_listen_saddr(InetSocketAddress *saddr, int port_offset, + int num, Error **errp) { struct addrinfo ai,*res,*e; @@ -309,7 +311,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr, goto listen_failed; } } else { - if (!listen(slisten, 1)) { + if (!listen(slisten, num)) { goto listen_ok; } if (errno != EADDRINUSE) { @@ -774,6 +776,7 @@ static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp) } static int vsock_listen_saddr(VsockSocketAddress *vaddr, + int num, Error **errp) { struct sockaddr_vm svm; @@ -795,7 +798,7 @@ static int vsock_listen_saddr(VsockSocketAddress *vaddr, return -1; } - if (listen(slisten, 1) != 0) { + if (listen(slisten, num) != 0) { error_setg_errno(errp, errno, "Failed to listen on socket"); closesocket(slisten); return -1; @@ -836,6 +839,7 @@ static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp) } static int vsock_listen_saddr(VsockSocketAddress *vaddr, + int num, Error **errp) { vsock_unsupported(errp); @@ -853,6 +857,7 @@ static int vsock_parse(VsockSocketAddress *addr, const char *str, #ifndef _WIN32 static int unix_listen_saddr(UnixSocketAddress *saddr, + int num, Error **errp) { struct sockaddr_un un; @@ -914,7 +919,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, error_setg_errno(errp, errno, "Failed to bind socket to %s", path); goto err; } - if (listen(sock, 1) < 0) { + if (listen(sock, num) < 0) { error_setg_errno(errp, errno, "Failed to listen on socket"); goto err; } @@ -981,6 +986,7 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) #else static int unix_listen_saddr(UnixSocketAddress *saddr, + int num, Error **errp) { error_setg(errp, "unix sockets are not available on windows"); @@ -1004,7 +1010,7 @@ int unix_listen(const char *str, Error **errp) saddr = g_new0(UnixSocketAddress, 1); saddr->path = g_strdup(str); - sock = unix_listen_saddr(saddr, errp); + sock = unix_listen_saddr(saddr, 1, errp); qapi_free_UnixSocketAddress(saddr); return sock; } @@ -1061,9 +1067,13 @@ fail: return NULL; } -static int socket_get_fd(const char *fdstr, Error **errp) +static int socket_get_fd(const char *fdstr, int num, Error **errp) { int fd; + if (num != 1) { + error_setg_errno(errp, EINVAL, "socket_get_fd: too many connections"); + return -1; + } if (cur_mon) { fd = monitor_get_fd(cur_mon, fdstr, errp); if (fd < 0) { @@ -1099,7 +1109,7 @@ int socket_connect(SocketAddress *addr, Error **errp) break; case SOCKET_ADDRESS_TYPE_FD: - fd = socket_get_fd(addr->u.fd.str, errp); + fd = socket_get_fd(addr->u.fd.str, 1, errp); break; case SOCKET_ADDRESS_TYPE_VSOCK: @@ -1112,25 +1122,26 @@ int socket_connect(SocketAddress *addr, Error **errp) return fd; } -int socket_listen(SocketAddress *addr, Error **errp) +int socket_listen(SocketAddress *addr, int num, Error **errp) { int fd; + trace_socket_listen(num); switch (addr->type) { case SOCKET_ADDRESS_TYPE_INET: - fd = inet_listen_saddr(&addr->u.inet, 0, errp); + fd = inet_listen_saddr(&addr->u.inet, 0, num, errp); break; case SOCKET_ADDRESS_TYPE_UNIX: - fd = unix_listen_saddr(&addr->u.q_unix, errp); + fd = unix_listen_saddr(&addr->u.q_unix, num, errp); break; case SOCKET_ADDRESS_TYPE_FD: - fd = socket_get_fd(addr->u.fd.str, errp); + fd = socket_get_fd(addr->u.fd.str, num, errp); break; case SOCKET_ADDRESS_TYPE_VSOCK: - fd = vsock_listen_saddr(&addr->u.vsock, errp); + fd = vsock_listen_saddr(&addr->u.vsock, num, errp); break; default: diff --git a/util/trace-events b/util/trace-events index 9dbd237dad..83b6639018 100644 --- a/util/trace-events +++ b/util/trace-events @@ -64,6 +64,9 @@ lockcnt_futex_wait(const void *lockcnt, int val) "lockcnt %p waiting on %d" lockcnt_futex_wait_resume(const void *lockcnt, int new) "lockcnt %p after wait: %d" lockcnt_futex_wake(const void *lockcnt) "lockcnt %p waking up one waiter" +# qemu-sockets.c +socket_listen(int num) "backlog: %d" + # qemu-thread-common.h qemu_mutex_lock(void *mutex, const char *file, const int line) "waiting on mutex %p (%s:%d)" qemu_mutex_locked(void *mutex, const char *file, const int line) "taken mutex %p (%s:%d)" |