diff options
220 files changed, 2651 insertions, 1464 deletions
diff --git a/.gitlab-ci.d/check-dco.py b/.gitlab-ci.d/check-dco.py index d221b16bd5..70dec7d6ee 100755 --- a/.gitlab-ci.d/check-dco.py +++ b/.gitlab-ci.d/check-dco.py @@ -78,7 +78,10 @@ of Origin 1.1 (DCO): To indicate acceptance of the DCO every commit must have a tag - Signed-off-by: REAL NAME <EMAIL> + Signed-off-by: YOUR NAME <EMAIL> + +where "YOUR NAME" is your commonly known identity in the context +of the community. This can be achieved by passing the "-s" flag to the "git commit" command. diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml index 9427302383..a9e43e21d0 100644 --- a/.gitlab-ci.d/cirrus.yml +++ b/.gitlab-ci.d/cirrus.yml @@ -67,8 +67,6 @@ aarch64-macos-build: CIRRUS_VM_INSTANCE_TYPE: macos_instance CIRRUS_VM_IMAGE_SELECTOR: image CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-runner:sonoma - CIRRUS_VM_CPUS: 12 - CIRRUS_VM_RAM: 24G UPDATE_COMMAND: brew update INSTALL_COMMAND: brew install PATH_EXTRA: /opt/homebrew/ccache/libexec:/opt/homebrew/gettext/bin diff --git a/.gitlab-ci.d/crossbuild-template.yml b/.gitlab-ci.d/crossbuild-template.yml index 45a9810355..303943f818 100644 --- a/.gitlab-ci.d/crossbuild-template.yml +++ b/.gitlab-ci.d/crossbuild-template.yml @@ -57,7 +57,7 @@ extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG - timeout: 30m + timeout: 60m cache: paths: - ccache/ diff --git a/MAINTAINERS b/MAINTAINERS index 095420f8b0..2b1c4abed6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -994,6 +994,7 @@ F: hw/arm/virt* F: include/hw/arm/virt.h F: docs/system/arm/virt.rst F: tests/functional/test_aarch64_virt.py +F: tests/functional/test_aarch64_tuxrun.py F: tests/functional/test_arm_tuxrun.py Xilinx Zynq @@ -3338,6 +3339,10 @@ F: rust/qemu-api F: rust/qemu-api-macros F: rust/rustfmt.toml +Rust-related patches CC here +L: qemu-rust@nongnu.org +F: rust/ + SLIRP M: Samuel Thibault <samuel.thibault@ens-lyon.org> S: Maintained @@ -3559,7 +3564,7 @@ F: include/migration/failover.h F: docs/COLO-FT.txt COLO Proxy -M: Zhang Chen <chen.zhang@intel.com> +M: Zhang Chen <zhangckid@gmail.com> M: Li Zhijian <lizhijian@fujitsu.com> S: Supported F: docs/colo-proxy.txt @@ -3747,6 +3752,7 @@ F: plugins/ F: tests/tcg/plugins/ F: tests/functional/test_aarch64_tcg_plugins.py F: contrib/plugins/ +F: scripts/qemu-plugin-symbols.py AArch64 TCG target M: Richard Henderson <richard.henderson@linaro.org> @@ -4125,7 +4131,7 @@ F: scripts/ci/ F: tests/docker/ F: tests/vm/ F: tests/lcitool/ -F: tests/avocado/tuxrun_baselines.py +F: tests/functional/test_*_tuxrun.py F: scripts/archive-source.sh F: docs/devel/testing.rst W: https://gitlab.com/qemu-project/qemu/pipelines @@ -4241,6 +4247,7 @@ F: docs/devel/docs.rst Rust build system integration M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> +L: qemu-rust@nongnu.org S: Maintained F: scripts/rust/ F: rust/.gitignore diff --git a/VERSION b/VERSION index 46b58d60c8..66ef6dc74e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -9.1.90 +9.1.92 diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index aa8af52cc3..06016eb030 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -800,7 +800,7 @@ static int probe_access_internal(CPUArchState *env, vaddr addr, if (guest_addr_valid_untagged(addr)) { int page_flags = page_get_flags(addr); if (page_flags & acc_flag) { - if ((acc_flag == PAGE_READ || acc_flag == PAGE_WRITE) + if (access_type != MMU_INST_FETCH && cpu_plugin_mem_cbs_enabled(env_cpu(env))) { return TLB_MMIO; } diff --git a/block/parallels.c b/block/parallels.c index 9205a0864f..071b6dcaf8 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -184,11 +184,11 @@ static int mark_used(BlockDriverState *bs, unsigned long *bitmap, BDRVParallelsState *s = bs->opaque; uint32_t cluster_index = host_cluster_index(s, off); unsigned long next_used; - if (cluster_index + count > bitmap_size) { + if ((uint64_t)cluster_index + count > bitmap_size) { return -E2BIG; } next_used = find_next_bit(bitmap, bitmap_size, cluster_index); - if (next_used < cluster_index + count) { + if (next_used < (uint64_t)cluster_index + count) { return -EBUSY; } bitmap_set(bitmap, cluster_index, count); diff --git a/block/ssh.c b/block/ssh.c index 9f8140bcb6..b9f33ec739 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -866,9 +866,6 @@ static int ssh_open(BlockDriverState *bs, QDict *options, int bdrv_flags, goto err; } - /* Go non-blocking. */ - ssh_set_blocking(s->session, 0); - if (s->attrs->type == SSH_FILEXFER_TYPE_REGULAR) { bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; } diff --git a/chardev/char-mux.c b/chardev/char-mux.c index bda5c45e60..e13042d381 100644 --- a/chardev/char-mux.c +++ b/chardev/char-mux.c @@ -316,6 +316,8 @@ bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b, { unsigned int bit; + QEMU_BUILD_BUG_ON(MAX_MUX > (sizeof(d->mux_bitset) * BITS_PER_BYTE)); + bit = find_next_zero_bit(&d->mux_bitset, MAX_MUX, 0); if (bit >= MAX_MUX) { error_setg(errp, @@ -325,7 +327,7 @@ bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b, return false; } - d->mux_bitset |= (1 << bit); + d->mux_bitset |= (1ul << bit); d->backends[bit] = b; *tag = bit; @@ -334,15 +336,12 @@ bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b, bool mux_chr_detach_frontend(MuxChardev *d, unsigned int tag) { - unsigned int bit; - - bit = find_next_bit(&d->mux_bitset, MAX_MUX, tag); - if (bit != tag) { + if (!(d->mux_bitset & (1ul << tag))) { return false; } - d->mux_bitset &= ~(1 << bit); - d->backends[bit] = NULL; + d->mux_bitset &= ~(1ul << tag); + d->backends[tag] = NULL; return true; } @@ -351,7 +350,7 @@ void mux_set_focus(Chardev *chr, unsigned int focus) { MuxChardev *d = MUX_CHARDEV(chr); - assert(find_next_bit(&d->mux_bitset, MAX_MUX, focus) == focus); + assert(d->mux_bitset & (1ul << focus)); if (d->focus != -1) { mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); diff --git a/configure b/configure index 096b1fddb7..18336376bf 100755 --- a/configure +++ b/configure @@ -13,7 +13,7 @@ export CCACHE_RECACHE=yes # make source path absolute source_path=$(cd "$(dirname -- "$0")"; pwd) -if test "$PWD" = "$source_path" +if test "$PWD" -ef "$source_path" then echo "Using './build' as the directory for build output" diff --git a/cpu-common.c b/cpu-common.c index 6b262233a3..0d607bbe49 100644 --- a/cpu-common.c +++ b/cpu-common.c @@ -194,6 +194,9 @@ void start_exclusive(void) CPUState *other_cpu; int running_cpus; + /* Ensure we are not running, or start_exclusive will be blocked. */ + g_assert(!current_cpu->running); + if (current_cpu->exclusive_context_count) { current_cpu->exclusive_context_count++; return; diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst index 6102f00aec..d8b0445157 100644 --- a/docs/about/build-platforms.rst +++ b/docs/about/build-platforms.rst @@ -40,7 +40,7 @@ Those hosts are officially supported, with various accelerators: * - CPU Architecture - Accelerators * - Arm - - kvm (64 bit only), tcg, xen + - hvf (64 bit only), kvm (64 bit only), tcg, xen * - MIPS (64 bit little endian only) - kvm, tcg * - PPC diff --git a/docs/devel/submitting-a-patch.rst b/docs/devel/submitting-a-patch.rst index 83e9092b8c..10b062eec2 100644 --- a/docs/devel/submitting-a-patch.rst +++ b/docs/devel/submitting-a-patch.rst @@ -18,7 +18,7 @@ one-shot fix, the bare minimum we ask is that: * - Check - Reason - * - Patches contain Signed-off-by: Real Name <author@email> + * - Patches contain Signed-off-by: Your Name <author@email> - States you are legally able to contribute the code. See :ref:`patch_emails_must_include_a_signed_off_by_line` * - Sent as patch emails to ``qemu-devel@nongnu.org`` - The project uses an email list based workflow. See :ref:`submitting_your_patches` @@ -335,6 +335,11 @@ include a "From:" line in the body of the email (different from your envelope From:) that will give credit to the correct author; but again, that author's Signed-off-by: line is mandatory, with the same spelling. +The name used with "Signed-off-by" does not need to be your legal name, +nor birth name, nor appear on any government ID. It is the identity you +choose to be known by in the community, but should not be anonymous, +nor misrepresent whom you are. + There are various tooling options for automatically adding these tags include using ``git commit -s`` or ``git format-patch -s``. For more information see `SubmittingPatches 1.12 diff --git a/docs/devel/testing/functional.rst b/docs/devel/testing/functional.rst index bf6f1bb81e..ae238ed3fc 100644 --- a/docs/devel/testing/functional.rst +++ b/docs/devel/testing/functional.rst @@ -59,11 +59,18 @@ To run a single test file without the meson test runner, you can also execute the file directly by specifying two environment variables first, the PYTHONPATH that has to include the python folder and the tests/functional folder of the source tree, and QEMU_TEST_QEMU_BINARY that has to point -to the QEMU binary that should be used for the test, for example:: +to the QEMU binary that should be used for the test. The current working +directory should be your build folder. For example:: $ export PYTHONPATH=../python:../tests/functional $ export QEMU_TEST_QEMU_BINARY=$PWD/qemu-system-x86_64 - $ python3 ../tests/functional/test_file.py + $ pyvenv/bin/python3 ../tests/functional/test_file.py + +The test framework will automatically purge any scratch files created during +the tests. If needing to debug a failed test, it is possible to keep these +files around on disk by setting ```QEMU_TEST_KEEP_SCRATCH=1``` as an env +variable. Any preserved files will be deleted the next time the test is run +without this variable set. Overview -------- @@ -170,6 +177,16 @@ primarily depend on the value of the ``qemu_bin`` class attribute. If it is not explicitly set by the test code, its default value will be the result the QEMU_TEST_QEMU_BINARY environment variable. +Debugging hung QEMU +^^^^^^^^^^^^^^^^^^^ + +When test cases go wrong it may be helpful to debug a stalled QEMU +process. While the QEMUMachine class owns the primary QMP monitor +socket, it is possible to request a second QMP monitor be created +by setting the ``QEMU_TEST_QMP_BACKDOOR`` env variable to refer +to a UNIX socket name. The ``qmp-shell`` command can then be +attached to the stalled QEMU to examine its live state. + Attribute reference ------------------- diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index 63910d382f..d17fe7a4fc 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -1,5 +1,5 @@ -Aspeed family boards (``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``, ``bletchley-bmc``, ``fuji-bmc``, ``fby35-bmc``, ``fp5280g2-bmc``, ``g220a-bmc``, ``palmetto-bmc``, ``qcom-dc-scm-v1-bmc``, ``qcom-firework-bmc``, ``quanta-q71l-bmc``, ``rainier-bmc``, ``romulus-bmc``, ``sonorapass-bmc``, ``supermicrox11-bmc``, ``tiogapass-bmc``, ``tacoma-bmc``, ``witherspoon-bmc``, ``yosemitev2-bmc``) -======================================================================================================================================================================================================================================================================================================================================================================================================== +Aspeed family boards (``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``, ``bletchley-bmc``, ``fuji-bmc``, ``fby35-bmc``, ``fp5280g2-bmc``, ``g220a-bmc``, ``palmetto-bmc``, ``qcom-dc-scm-v1-bmc``, ``qcom-firework-bmc``, ``quanta-q71l-bmc``, ``rainier-bmc``, ``romulus-bmc``, ``sonorapass-bmc``, ``supermicrox11-bmc``, ``supermicrox11spi-bmc``, ``tiogapass-bmc``, ``tacoma-bmc``, ``witherspoon-bmc``, ``yosemitev2-bmc``) +================================================================================================================================================================================================================================================================================================================================================================================================================================== The QEMU Aspeed machines model BMCs of various OpenPOWER systems and Aspeed evaluation boards. They are based on different releases of the @@ -15,7 +15,8 @@ AST2400 SoC based machines : - ``palmetto-bmc`` OpenPOWER Palmetto POWER8 BMC - ``quanta-q71l-bmc`` OpenBMC Quanta BMC -- ``supermicrox11-bmc`` Supermicro X11 BMC +- ``supermicrox11-bmc`` Supermicro X11 BMC (ARM926EJ-S) +- ``supermicrox11spi-bmc`` Supermicro X11 SPI BMC (ARM1176) AST2500 SoC based machines : @@ -105,6 +106,9 @@ or directly from the ASPEED Forked OpenBMC GitHub release repository : https://github.com/AspeedTech-BMC/openbmc/releases +Booting from a kernel image +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + To boot a kernel directly from a Linux build tree: .. code-block:: bash @@ -114,16 +118,10 @@ To boot a kernel directly from a Linux build tree: -dtb arch/arm/boot/dts/aspeed-ast2600-evb.dtb \ -initrd rootfs.cpio -To boot the machine from the flash image, use an MTD drive : - -.. code-block:: bash - - $ qemu-system-arm -M romulus-bmc -nic user \ - -drive file=obmc-phosphor-image-romulus.static.mtd,format=raw,if=mtd -nographic +Booting from a flash image +^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Options specific to Aspeed machines are : - - * ``boot-emmc`` to set or unset boot from eMMC (AST2600). +The machine options specific to Aspeed to boot from a flash image are : * ``execute-in-place`` which emulates the boot from the CE0 flash device by using the FMC controller to load the instructions, and @@ -134,10 +132,12 @@ Options specific to Aspeed machines are : * ``spi-model`` to change the default SPI Flash model. - * ``bmc-console`` to change the default console device. Most of the - machines use the ``UART5`` device for a boot console, which is - mapped on ``/dev/ttyS4`` under Linux, but it is not always the - case. +To boot the machine from the flash image, use an MTD drive : + +.. code-block:: bash + + $ qemu-system-arm -M romulus-bmc -nic user \ + -drive file=obmc-phosphor-image-romulus.static.mtd,format=raw,if=mtd -nographic To use other flash models, for instance a different FMC chip and a bigger (64M) SPI for the ``ast2500-evb`` machine, run : @@ -169,6 +169,78 @@ In that case, the machine boots fetching instructions from the FMC0 device. It is slower to start but closer to what HW does. Using the machine option ``execute-in-place`` has a similar effect. +Booting from an eMMC image +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The machine options specific to Aspeed machines to boot from an eMMC +image are : + + * ``boot-emmc`` to set or unset boot from eMMC (AST2600). + +Only the ``ast2600-evb`` and ``rainier-emmc`` machines have support to +boot from an eMMC device. In this case, the machine assumes that the +eMMC image includes special boot partitions. Such an image can be +built this way : + +.. code-block:: bash + + $ dd if=/dev/zero of=mmc-bootarea.img count=2 bs=1M + $ dd if=u-boot-spl.bin of=mmc-bootarea.img conv=notrunc + $ dd if=u-boot.bin of=mmc-bootarea.img conv=notrunc count=64 bs=1K + $ cat mmc-bootarea.img obmc-phosphor-image.wic > mmc.img + $ truncate --size 16GB mmc.img + +Boot the machine ``rainier-emmc`` with : + +.. code-block:: bash + + $ qemu-system-arm -M rainier-bmc \ + -drive file=mmc.img,format=raw,if=sd,index=2 \ + -nographic + +The ``boot-emmc`` option can be set or unset, to change the default +boot mode of machine: SPI or eMMC. This can be useful to boot the +``ast2600-evb`` machine from an eMMC device (default being SPI) or to +boot the ``rainier-bmc`` machine from a flash device (default being +eMMC). + +As an example, here is how to to boot the ``rainier-bmc`` machine from +the flash device with ``boot-emmc=false`` and let the machine use an +eMMC image : + +.. code-block:: bash + + $ qemu-system-arm -M rainier-bmc,boot-emmc=false \ + -drive file=flash.img,format=raw,if=mtd \ + -drive file=mmc.img,format=raw,if=sd,index=2 \ + -nographic + +It should be noted that in this case the eMMC device must not have +boot partitions, otherwise the contents will not be accessible to the +machine. This limitation is due to the use of the ``-drive`` +interface. + +Ideally, one should be able to define the eMMC device and the +associated backend directly on the command line, such as : + +.. code-block:: bash + + -blockdev node-name=emmc0,driver=file,filename=mmc.img \ + -device emmc,bus=sdhci-bus.2,drive=emmc0,boot-partition-size=1048576,boot-config=8 + +This is not yet supported (as of QEMU-10.0). Work is needed to +refactor the sdhci bus model. + +Other booting options +^^^^^^^^^^^^^^^^^^^^^ + +Other machine options specific to Aspeed machines are : + + * ``bmc-console`` to change the default console device. Most of the + machines use the ``UART5`` device for a boot console, which is + mapped on ``/dev/ttyS4`` under Linux, but it is not always the + case. + To change the boot console and use device ``UART3`` (``/dev/ttyS2`` under Linux), use : @@ -176,6 +248,8 @@ under Linux), use : -M ast2500-evb,bmc-console=uart3 +Booting the ast2700-evb machine +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Boot the AST2700 machine from the flash image, use an MTD drive : diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index a2a388f091..38534dcdd3 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -3,8 +3,8 @@ A-profile CPU architecture support ================================== -QEMU's TCG emulation includes support for the Armv5, Armv6, Armv7 and -Armv8 versions of the A-profile architecture. It also has support for +QEMU's TCG emulation includes support for the Armv5, Armv6, Armv7, +Armv8 and Armv9 versions of the A-profile architecture. It also has support for the following architecture extensions: - FEAT_AA32BF16 (AArch32 BFloat16 instructions) @@ -37,6 +37,7 @@ the following architecture extensions: - FEAT_CSV3 (Cache speculation variant 3) - FEAT_DGH (Data gathering hint) - FEAT_DIT (Data Independent Timing instructions) +- FEAT_DoubleLock (Double Lock) - FEAT_DPB (DC CVAP instruction) - FEAT_DPB2 (DC CVADP instruction) - FEAT_Debugv8p1 (Debug with VHE) @@ -88,12 +89,13 @@ the following architecture extensions: - FEAT_LSE2 (Large System Extensions v2) - FEAT_LVA (Large Virtual Address space) - FEAT_MixedEnd (Mixed-endian support) -- FEAT_MixdEndEL0 (Mixed-endian support at EL0) +- FEAT_MixedEndEL0 (Mixed-endian support at EL0) - FEAT_MOPS (Standardization of memory operations) - FEAT_MTE (Memory Tagging Extension) - FEAT_MTE2 (Memory Tagging Extension) - FEAT_MTE3 (MTE Asymmetric Fault Handling) - FEAT_MTE_ASYM_FAULT (Memory tagging asymmetric faults) +- FEAT_MTE_ASYNC (Asynchronous reporting of Tag Check Fault) - FEAT_NMI (Non-maskable Interrupt) - FEAT_NV (Nested Virtualization) - FEAT_NV2 (Enhanced nested virtualization support) @@ -137,6 +139,7 @@ the following architecture extensions: - FEAT_SVE2 (Scalable Vector Extension version 2) - FEAT_SPECRES (Speculation restriction instructions) - FEAT_SSBS (Speculative Store Bypass Safe) +- FEAT_SSBS2 (MRS and MSR instructions for SSBS version 2) - FEAT_TGran16K (Support for 16KB memory translation granule size at stage 1) - FEAT_TGran4K (Support for 4KB memory translation granule size at stage 1) - FEAT_TGran64K (Support for 64KB memory translation granule size at stage 1) @@ -153,7 +156,7 @@ the following architecture extensions: - FEAT_XNX (Translation table stage 2 Unprivileged Execute-never) For information on the specifics of these extensions, please refer -to the `Armv8-A Arm Architecture Reference Manual +to the `Arm Architecture Reference Manual for A-profile architecture <https://developer.arm.com/documentation/ddi0487/latest>`_. When a specific named CPU is being emulated, only those features which diff --git a/docs/system/arm/fby35.rst b/docs/system/arm/fby35.rst index 742b887d44..bf6da6baa2 100644 --- a/docs/system/arm/fby35.rst +++ b/docs/system/arm/fby35.rst @@ -12,7 +12,7 @@ include various compute accelerators (video, inferencing, etc). At the moment, only the first server slot's BIC is included. Yosemite v3.5 is itself a sled which fits into a 40U chassis, and 3 sleds -can be fit into a chassis. See `here <https://www.opencompute.org/products/423/wiwynn-yosemite-v3-server>`__ +can be fit into a chassis. See `here <https://www.opencompute.org/products-chiplets/237/wiwynn-yosemite-v3-server>`__ for an example. In this generation, the BMC is an AST2600 and each BIC is an AST1030. The BMC diff --git a/docs/system/bootindex.rst b/docs/system/bootindex.rst index 988f7b3beb..5e1b33ee22 100644 --- a/docs/system/bootindex.rst +++ b/docs/system/bootindex.rst @@ -53,7 +53,7 @@ booting. For instance, the x86 PC BIOS boot specification allows only one disk to be bootable. If boot from disk fails for some reason, the x86 BIOS won't retry booting from other disk. It can still try to boot from floppy or net, though. In the case of s390x BIOS, the BIOS will try up to -8 total devices, any number of which may be disks. +8 total devices, any number of which may be disks or virtio-net devices. Sometimes, firmware cannot map the device path QEMU wants firmware to boot from to a boot method. It doesn't happen for devices the firmware diff --git a/docs/system/s390x/bootdevices.rst b/docs/system/s390x/bootdevices.rst index 1a1a764c1c..97b3914785 100644 --- a/docs/system/s390x/bootdevices.rst +++ b/docs/system/s390x/bootdevices.rst @@ -79,7 +79,29 @@ The second way to use this parameter is to use a number in the range from 0 to 31. The numbers that can be used here correspond to the numbers that are shown when using the ``PROMPT`` option, and the s390-ccw bios will then try to automatically boot the kernel that is associated with the given number. -Note that ``0`` can be used to boot the default entry. +Note that ``0`` can be used to boot the default entry. If the machine +``loadparm`` is not assigned a value, then the default entry is used. + +By default, the machine ``loadparm`` applies to all boot devices. If multiple +devices are assigned a ``bootindex`` and the ``loadparm`` is to be different +between them, an independent ``loadparm`` may be assigned on a per-device basis. + +An example guest using per-device ``loadparm``:: + + qemu-system-s390x -drive if=none,id=dr1,file=primary.qcow2 \ + -device virtio-blk,drive=dr1,bootindex=1 \ + -drive if=none,id=dr2,file=secondary.qcow2 \ + -device virtio-blk,drive=dr2,bootindex=2,loadparm=3 + +In this case, the primary boot device will attempt to IPL using the default +entry (because no ``loadparm`` is specified for this device or for the +machine). If that device fails to boot, the secondary device will attempt to +IPL using entry number 3. + +If a ``loadparm`` is specified on both the machine and a device, the per-device +value will superseded the machine value. Per-device ``loadparm`` values are +only used for devices with an assigned ``bootindex``. The machine ``loadparm`` +is used when attempting to boot without a ``bootindex``. Booting from a network device diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index b5a3208050..9bca03c4ae 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -597,6 +597,25 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, float_raise(float_flag_invalid | float_flag_invalid_imz, status); } return 3; /* default NaN */ +#elif defined(TARGET_S390X) + if (infzero) { + float_raise(float_flag_invalid | float_flag_invalid_imz, status); + return 3; + } + + if (is_snan(a_cls)) { + return 0; + } else if (is_snan(b_cls)) { + return 1; + } else if (is_snan(c_cls)) { + return 2; + } else if (is_qnan(a_cls)) { + return 0; + } else if (is_qnan(b_cls)) { + return 1; + } else { + return 2; + } #elif defined(TARGET_SPARC) /* For (inf,0,nan) return c. */ if (infzero) { diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 9a291d1b51..578517739a 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1596,11 +1596,13 @@ static void coroutine_fn v9fs_getattr(void *opaque) retval = -ENOENT; goto out_nofid; } - /* - * Currently we only support BASIC fields in stat, so there is no - * need to look at request_mask. - */ - retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf); + if ((fidp->fid_type == P9_FID_FILE && fidp->fs.fd != -1) || + (fidp->fid_type == P9_FID_DIR && fidp->fs.dir.stream)) + { + retval = v9fs_co_fstat(pdu, fidp, &stbuf); + } else { + retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf); + } if (retval < 0) { goto out; } diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index a6f59abccb..5e041e1f60 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -280,7 +280,6 @@ struct V9fsFidState { uid_t uid; int ref; bool clunked; - QSIMPLEQ_ENTRY(V9fsFidState) next; QSLIST_ENTRY(V9fsFidState) reclaim_next; }; diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 6a76626177..72282b173e 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1960,7 +1960,7 @@ static void build_append_srat_acpi_device_handle(GArray *table_data, { assert(strlen(hid) == 8); /* Device Handle - ACPI */ - for (int i = 0; i < sizeof(hid); i++) { + for (int i = 0; i < 8; i++) { build_append_int_noprefix(table_data, hid[i], 1); } build_append_int_noprefix(table_data, uid, 4); diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index 23443f09a5..5cb60ca8bc 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -50,18 +50,6 @@ void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list) } } -static bool check_cpu_enabled_status(DeviceState *dev) -{ - CPUClass *k = dev ? CPU_GET_CLASS(dev) : NULL; - CPUState *cpu = CPU(dev); - - if (cpu && (!k->cpu_enabled_status || k->cpu_enabled_status(cpu))) { - return true; - } - - return false; -} - static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size) { uint64_t val = 0; @@ -75,11 +63,10 @@ static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size) cdev = &cpu_st->devs[cpu_st->selector]; switch (addr) { case ACPI_CPU_FLAGS_OFFSET_RW: /* pack and return is_* fields */ - val |= check_cpu_enabled_status(DEVICE(cdev->cpu)) ? 1 : 0; + val |= cdev->cpu ? 1 : 0; val |= cdev->is_inserting ? 2 : 0; val |= cdev->is_removing ? 4 : 0; val |= cdev->fw_remove ? 16 : 0; - val |= cdev->cpu ? 32 : 0; trace_cpuhp_acpi_read_flags(cpu_st->selector, val); break; case ACPI_CPU_CMD_DATA_OFFSET_RW: @@ -246,17 +233,6 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, memory_region_add_subregion(as, base_addr, &state->ctrl_reg); } -static bool should_remain_acpi_present(DeviceState *dev) -{ - CPUClass *k = CPU_GET_CLASS(dev); - /* - * A system may contain CPUs that are always present on one die, NUMA node, - * or socket, yet may be non-present on another simultaneously. Check from - * architecture specific code. - */ - return k->cpu_persistent_status && k->cpu_persistent_status(CPU(dev)); -} - static AcpiCpuStatus *get_cpu_status(CPUHotplugState *cpu_st, DeviceState *dev) { CPUClass *k = CPU_GET_CLASS(dev); @@ -313,9 +289,7 @@ void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st, return; } - if (!should_remain_acpi_present(dev)) { - cdev->cpu = NULL; - } + cdev->cpu = NULL; } static const VMStateDescription vmstate_cpuhp_sts = { @@ -362,7 +336,6 @@ const VMStateDescription vmstate_cpu_hotplug = { #define CPU_REMOVE_EVENT "CRMV" #define CPU_EJECT_EVENT "CEJ0" #define CPU_FW_EJECT_EVENT "CEJF" -#define CPU_PRESENT "CPRS" void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, build_madt_cpu_fn build_madt_cpu, hwaddr base_addr, @@ -423,9 +396,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, aml_append(field, aml_named_field(CPU_EJECT_EVENT, 1)); /* tell firmware to do device eject, write only */ aml_append(field, aml_named_field(CPU_FW_EJECT_EVENT, 1)); - /* 1 if present, read only */ - aml_append(field, aml_named_field(CPU_PRESENT, 1)); - aml_append(field, aml_reserved_field(2)); + aml_append(field, aml_reserved_field(3)); aml_append(field, aml_named_field(CPU_COMMAND, 8)); aml_append(cpu_ctrl_dev, field); @@ -455,7 +426,6 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, Aml *ctrl_lock = aml_name("%s.%s", cphp_res_path, CPU_LOCK); Aml *cpu_selector = aml_name("%s.%s", cphp_res_path, CPU_SELECTOR); Aml *is_enabled = aml_name("%s.%s", cphp_res_path, CPU_ENABLED); - Aml *is_present = aml_name("%s.%s", cphp_res_path, CPU_PRESENT); Aml *cpu_cmd = aml_name("%s.%s", cphp_res_path, CPU_COMMAND); Aml *cpu_data = aml_name("%s.%s", cphp_res_path, CPU_DATA); Aml *ins_evt = aml_name("%s.%s", cphp_res_path, CPU_INSERT_EVENT); @@ -484,26 +454,13 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, { Aml *idx = aml_arg(0); Aml *sta = aml_local(0); - Aml *ifctx2; - Aml *else_ctx; aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); aml_append(method, aml_store(idx, cpu_selector)); aml_append(method, aml_store(zero, sta)); - ifctx = aml_if(aml_equal(is_present, one)); + ifctx = aml_if(aml_equal(is_enabled, one)); { - ifctx2 = aml_if(aml_equal(is_enabled, one)); - { - /* cpu is present and enabled */ - aml_append(ifctx2, aml_store(aml_int(0xF), sta)); - } - aml_append(ifctx, ifctx2); - else_ctx = aml_else(); - { - /* cpu is present but disabled */ - aml_append(else_ctx, aml_store(aml_int(0xD), sta)); - } - aml_append(ifctx, else_ctx); + aml_append(ifctx, aml_store(aml_int(0xF), sta)); } aml_append(method, ifctx); aml_append(method, aml_release(ctrl_lock)); diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c index bc661504cf..c340a9481d 100644 --- a/hw/audio/hda-codec.c +++ b/hw/audio/hda-codec.c @@ -472,24 +472,6 @@ static void hda_audio_set_amp(HDAAudioStream *st) } } -static void hda_close_stream(HDAAudioState *a, HDAAudioStream *st) -{ - if (st->node == NULL) { - return; - } - if (a->use_timer) { - timer_free(st->buft); - st->buft = NULL; - } - if (st->output) { - AUD_close_out(&a->card, st->voice.out); - st->voice.out = NULL; - } else { - AUD_close_in(&a->card, st->voice.in); - st->voice.in = NULL; - } -} - static void hda_audio_setup(HDAAudioStream *st) { bool use_timer = st->state->use_timer; @@ -502,12 +484,10 @@ static void hda_audio_setup(HDAAudioStream *st) trace_hda_audio_format(st->node->name, st->as.nchannels, fmt2name[st->as.fmt], st->as.freq); - hda_close_stream(st->state, st); if (st->output) { if (use_timer) { cb = hda_audio_output_cb; - st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, - hda_audio_output_timer, st); + timer_del(st->buft); } else { cb = hda_audio_compat_output_cb; } @@ -516,8 +496,7 @@ static void hda_audio_setup(HDAAudioStream *st) } else { if (use_timer) { cb = hda_audio_input_cb; - st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, - hda_audio_input_timer, st); + timer_del(st->buft); } else { cb = hda_audio_compat_input_cb; } @@ -745,8 +724,12 @@ static void hda_audio_init(HDACodecDevice *hda, st->gain_right = QEMU_HDA_AMP_STEPS; st->compat_bpos = sizeof(st->compat_buf); st->output = true; + st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, + hda_audio_output_timer, st); } else { st->output = false; + st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, + hda_audio_input_timer, st); } st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 | (1 << AC_FMT_CHAN_SHIFT); @@ -760,11 +743,21 @@ static void hda_audio_init(HDACodecDevice *hda, static void hda_audio_exit(HDACodecDevice *hda) { HDAAudioState *a = HDA_AUDIO(hda); + HDAAudioStream *st; int i; dprint(a, 1, "%s\n", __func__); for (i = 0; i < ARRAY_SIZE(a->st); i++) { - hda_close_stream(a, a->st + i); + st = a->st + i; + if (st->node == NULL) { + continue; + } + timer_free(st->buft); + if (st->output) { + AUD_close_out(&a->card, st->voice.out); + } else { + AUD_close_in(&a->card, st->voice.in); + } } AUD_remove_card(&a->card); } diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c index 640b2114b4..b954eb8490 100644 --- a/hw/core/machine-smp.c +++ b/hw/core/machine-smp.c @@ -290,6 +290,7 @@ bool machine_parse_smp_cache(MachineState *ms, const SmpCachePropertiesList *node; DECLARE_BITMAP(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX); + bitmap_zero(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX); for (node = caches; node; node = node->next) { /* Prohibit users from repeating settings. */ if (test_bit(node->value->cache, caches_bitmap)) { @@ -316,7 +317,7 @@ bool machine_parse_smp_cache(MachineState *ms, !mc->smp_props.cache_supported[props->cache]) { error_setg(errp, "%s cache topology not supported by this machine", - CacheLevelAndType_str(node->value->cache)); + CacheLevelAndType_str(props->cache)); return false; } diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 35deef05f3..22ea1ed358 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -58,6 +58,32 @@ static bool check_prop_still_unset(Object *obj, const char *name, return false; } +bool qdev_prop_sanitize_s390x_loadparm(uint8_t *loadparm, const char *str, + Error **errp) +{ + int i, len; + + len = strlen(str); + if (len > 8) { + error_setg(errp, "'loadparm' can only contain up to 8 characters"); + return false; + } + + for (i = 0; i < len; i++) { + uint8_t c = qemu_toupper(str[i]); /* mimic HMC */ + + if (qemu_isalnum(c) || c == '.' || c == ' ') { + loadparm[i] = c; + } else { + error_setg(errp, + "invalid character in 'loadparm': '%c' (ASCII 0x%02x)", + c, c); + return false; + } + } + + return true; +} /* --- drive --- */ @@ -790,39 +816,57 @@ static void set_pci_devfn(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { Property *prop = opaque; + g_autofree GenericAlternate *alt; int32_t value, *ptr = object_field_prop_ptr(obj, prop); unsigned int slot, fn, n; - char *str; + g_autofree char *str = NULL; + + if (!visit_start_alternate(v, name, &alt, sizeof(*alt), errp)) { + return; + } - if (!visit_type_str(v, name, &str, NULL)) { + switch (alt->type) { + case QTYPE_QSTRING: + if (!visit_type_str(v, name, &str, errp)) { + goto out; + } + + if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { + fn = 0; + if (sscanf(str, "%x%n", &slot, &n) != 1) { + goto invalid; + } + } + if (str[n] != '\0' || fn > 7 || slot > 31) { + goto invalid; + } + *ptr = slot << 3 | fn; + break; + + case QTYPE_QNUM: if (!visit_type_int32(v, name, &value, errp)) { - return; + goto out; } if (value < -1 || value > 255) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", "a value between -1 and 255"); - return; + goto out; } *ptr = value; - return; - } + break; - if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { - fn = 0; - if (sscanf(str, "%x%n", &slot, &n) != 1) { - goto invalid; - } - } - if (str[n] != '\0' || fn > 7 || slot > 31) { - goto invalid; + default: + error_setg(errp, "Invalid parameter type for '%s', expected int or str", + name ? name : "null"); + goto out; } - *ptr = slot << 3 | fn; - g_free(str); - return; + + goto out; invalid: error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str); - g_free(str); +out: + visit_end_alternate(v, (void **) &alt); } static int print_pci_devfn(Object *obj, Property *prop, char *dest, diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 2d4d62c454..ce9aa18364 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -1288,6 +1288,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, set_feat_info->data_offset = hdr->offset; bytes_to_copy = len_in - sizeof(CXLSetFeatureInHeader); + if (bytes_to_copy == 0) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + if (qemu_uuid_is_equal(&hdr->uuid, &patrol_scrub_uuid)) { if (hdr->version != CXL_MEMDEV_PS_SET_FEATURE_VERSION) { return CXL_MBOX_UNSUPPORTED; diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index eedae7357f..145a0b3879 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -805,7 +805,6 @@ static void virgl_cmd_set_scanout_blob(VirtIOGPU *g, struct virtio_gpu_framebuffer fb = { 0 }; struct virtio_gpu_virgl_resource *res; struct virtio_gpu_set_scanout_blob ss; - uint64_t fbend; VIRTIO_GPU_FILL_CMD(ss); virtio_gpu_scanout_blob_bswap(&ss); @@ -852,26 +851,7 @@ static void virgl_cmd_set_scanout_blob(VirtIOGPU *g, return; } - fb.format = virtio_gpu_get_pixman_format(ss.format); - if (!fb.format) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: pixel format not supported %d\n", - __func__, ss.format); - cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; - return; - } - - fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8); - fb.width = ss.width; - fb.height = ss.height; - fb.stride = ss.strides[0]; - fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride; - - fbend = fb.offset; - fbend += fb.stride * (ss.r.height - 1); - fbend += fb.bytes_pp * ss.r.width; - if (fbend > res->base.blob_size) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: fb end out of range\n", - __func__); + if (!virtio_gpu_scanout_blob_to_fb(&fb, &ss, res->base.blob_size)) { cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; return; } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index c0570ef856..7d22d03bbf 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -721,13 +721,47 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, &fb, res, &ss.r, &cmd->error); } +bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb, + struct virtio_gpu_set_scanout_blob *ss, + uint64_t blob_size) +{ + uint64_t fbend; + + fb->format = virtio_gpu_get_pixman_format(ss->format); + if (!fb->format) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: host couldn't handle guest format %d\n", + __func__, ss->format); + return false; + } + + fb->bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb->format), 8); + fb->width = ss->width; + fb->height = ss->height; + fb->stride = ss->strides[0]; + fb->offset = ss->offsets[0] + ss->r.x * fb->bytes_pp + ss->r.y * fb->stride; + + fbend = fb->offset; + fbend += (uint64_t) fb->stride * ss->r.height; + + if (fbend > blob_size) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: fb end out of range\n", + __func__); + return false; + } + + return true; +} + + + static void virtio_gpu_set_scanout_blob(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { struct virtio_gpu_simple_resource *res; struct virtio_gpu_framebuffer fb = { 0 }; struct virtio_gpu_set_scanout_blob ss; - uint64_t fbend; VIRTIO_GPU_FILL_CMD(ss); virtio_gpu_scanout_blob_bswap(&ss); @@ -753,28 +787,7 @@ static void virtio_gpu_set_scanout_blob(VirtIOGPU *g, return; } - fb.format = virtio_gpu_get_pixman_format(ss.format); - if (!fb.format) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: host couldn't handle guest format %d\n", - __func__, ss.format); - cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; - return; - } - - fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8); - fb.width = ss.width; - fb.height = ss.height; - fb.stride = ss.strides[0]; - fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride; - - fbend = fb.offset; - fbend += fb.stride * (ss.r.height - 1); - fbend += fb.bytes_pp * ss.r.width; - if (fbend > res->blob_size) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: fb end out of range\n", - __func__); + if (!virtio_gpu_scanout_blob_to_fb(&fb, &ss, res->blob_size)) { cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; return; } diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 13af7211e1..af0f4da1f6 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1657,9 +1657,11 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp) error_report("AMD IOMMU with x2APIC confguration requires xtsup=on"); exit(EXIT_FAILURE); } - if (s->xtsup && kvm_irqchip_is_split() && !kvm_enable_x2apic()) { - error_report("AMD IOMMU xtsup=on requires support on the KVM side"); - exit(EXIT_FAILURE); + if (s->xtsup) { + if (kvm_irqchip_is_split() && !kvm_enable_x2apic()) { + error_report("AMD IOMMU xtsup=on requires support on the KVM side"); + exit(EXIT_FAILURE); + } } pci_setup_iommu(bus, &amdvi_iommu_ops, s); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index f9147fecbd..317aaca25a 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1228,7 +1228,6 @@ void pc_basic_device_init(struct PCMachineState *pcms, isa_realize_and_unref(pcms->pcspk, isa_bus, &error_fatal); } - assert(pcms->vmport >= 0 && pcms->vmport < ON_OFF_AUTO__MAX); if (pcms->vmport == ON_OFF_AUTO_AUTO) { pcms->vmport = (xen_enabled() || !pcms->i8042_enabled) ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c index bc360a9ea4..dc031af662 100644 --- a/hw/i386/x86-common.c +++ b/hw/i386/x86-common.c @@ -697,9 +697,11 @@ void x86_load_linux(X86MachineState *x86ms, strlen(kernel_cmdline) + 1); fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + setup = g_memdup2(header, sizeof(header)); + fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, sizeof(header)); fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, - header, sizeof(header)); + setup, sizeof(header)); /* load initrd */ if (initrd_filename) { diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c index 02dc4e6db3..97d1af5ccc 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -57,14 +57,9 @@ static void extioi_setirq(void *opaque, int irq, int level) LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); trace_loongarch_extioi_setirq(irq, level); if (level) { - /* - * s->isr should be used in vmstate structure, - * but it not support 'unsigned long', - * so we have to switch it. - */ - set_bit(irq, (unsigned long *)s->isr); + set_bit32(irq, s->isr); } else { - clear_bit(irq, (unsigned long *)s->isr); + clear_bit32(irq, s->isr); } extioi_update_irq(s, irq, level); } @@ -154,7 +149,7 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq, continue; } - if (notify && test_bit(irq + i, (unsigned long *)s->isr)) { + if (notify && test_bit32(irq + i, s->isr)) { /* * lower irq at old cpu and raise irq at new cpu */ diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index cd3d87768e..2ead4b9ba0 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -1031,13 +1031,14 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, s_IRQ = IRQ_get_next(opp, &dst->servicing); /* Check queued interrupts. */ n_IRQ = IRQ_get_next(opp, &dst->raised); - src = &opp->src[n_IRQ]; - if (n_IRQ != -1 && - (s_IRQ == -1 || - IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { - DPRINTF("Raise OpenPIC INT output cpu %d irq %d", - idx, n_IRQ); - qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]); + if (n_IRQ != -1) { + src = &opp->src[n_IRQ]; + if (s_IRQ == -1 || + IVPR_PRIORITY(src->ivpr) > dst->servicing.priority) { + DPRINTF("Raise OpenPIC INT output cpu %d irq %d", + idx, n_IRQ); + qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]); + } } break; default: diff --git a/hw/misc/nrf51_rng.c b/hw/misc/nrf51_rng.c index bf1eb0cf4a..2d67f3f766 100644 --- a/hw/misc/nrf51_rng.c +++ b/hw/misc/nrf51_rng.c @@ -107,25 +107,25 @@ static void rng_write(void *opaque, hwaddr offset, break; case NRF51_RNG_REG_SHORTS: s->shortcut_stop_on_valrdy = - (value & BIT_MASK(NRF51_RNG_REG_SHORTS_VALRDY_STOP)) ? 1 : 0; + (value & BIT(NRF51_RNG_REG_SHORTS_VALRDY_STOP)) ? 1 : 0; break; case NRF51_RNG_REG_INTEN: s->interrupt_enabled = - (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) ? 1 : 0; + (value & BIT(NRF51_RNG_REG_INTEN_VALRDY)) ? 1 : 0; break; case NRF51_RNG_REG_INTENSET: - if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) { + if (value & BIT(NRF51_RNG_REG_INTEN_VALRDY)) { s->interrupt_enabled = 1; } break; case NRF51_RNG_REG_INTENCLR: - if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) { + if (value & BIT(NRF51_RNG_REG_INTEN_VALRDY)) { s->interrupt_enabled = 0; } break; case NRF51_RNG_REG_CONFIG: s->filter_enabled = - (value & BIT_MASK(NRF51_RNG_REG_CONFIG_DECEN)) ? 1 : 0; + (value & BIT(NRF51_RNG_REG_CONFIG_DECEN)) ? 1 : 0; break; default: diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c index 5e16056be6..3378f63110 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -1635,8 +1635,8 @@ static int of_dpa_cmd_add_multicast_routing(OfDpaFlow *flow, return ROCKER_OK; } -static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask, - RockerTlv **flow_tlvs) +static void of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask, + RockerTlv **flow_tlvs) { key->width = FLOW_KEY_WIDTH(ip.tos); @@ -1669,8 +1669,6 @@ static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask, mask->ip.tos |= rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN_MASK]) << 6; } - - return ROCKER_OK; } static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs) @@ -1689,7 +1687,6 @@ static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs) ACL_MODE_ANY_VLAN, ACL_MODE_ANY_TENANT, } mode = ACL_MODE_UNKNOWN; - int err = ROCKER_OK; if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] || !flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]) { @@ -1776,14 +1773,10 @@ static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs) switch (ntohs(key->eth.type)) { case 0x0800: case 0x86dd: - err = of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs); + of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs); break; } - if (err) { - return err; - } - if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) { action->write.group_id = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]); diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 997aab0557..891f235a0a 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -229,10 +229,25 @@ static int vhost_net_enable_notifiers(VirtIODevice *dev, int nvhosts = data_queue_pairs + cvq; struct vhost_net *net; struct vhost_dev *hdev; - int r, i, j; + int r, i, j, k; NetClientState *peer; /* + * We will pass the notifiers to the kernel, make sure that QEMU + * doesn't interfere. + */ + for (i = 0; i < nvhosts; i++) { + r = virtio_device_grab_ioeventfd(dev); + if (r < 0) { + error_report("vhost %d binding does not support host notifiers", i); + for (k = 0; k < i; k++) { + virtio_device_release_ioeventfd(dev); + } + return r; + } + } + + /* * Batch all the host notifiers in a single transaction to avoid * quadratic time complexity in address_space_update_ioeventfds(). */ @@ -247,16 +262,6 @@ static int vhost_net_enable_notifiers(VirtIODevice *dev, net = get_vhost_net(peer); hdev = &net->dev; - /* - * We will pass the notifiers to the kernel, make sure that QEMU - * doesn't interfere. - */ - r = virtio_device_grab_ioeventfd(dev); - if (r < 0) { - error_report("binding does not support host notifiers"); - memory_region_transaction_commit(); - goto fail_nvhosts; - } for (j = 0; j < hdev->nvqs; j++) { r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), @@ -277,6 +282,14 @@ static int vhost_net_enable_notifiers(VirtIODevice *dev, return 0; fail_nvhosts: vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, i); + /* + * This for loop starts from i+1, not i, because the i-th ioeventfd + * has already been released in vhost_dev_disable_notifiers_nvqs(). + */ + for (k = i + 1; k < nvhosts; k++) { + virtio_device_release_ioeventfd(dev); + } + return r; } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index f2104ed364..6e8c51a2db 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1695,38 +1695,44 @@ static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr) * cache. */ static void work_around_broken_dhclient(struct virtio_net_hdr *hdr, - uint8_t *buf, size_t size) + size_t *hdr_len, const uint8_t *buf, + size_t buf_size, size_t *buf_offset) { + size_t csum_size = ETH_HLEN + sizeof(struct ip_header) + + sizeof(struct udp_header); + + buf += *buf_offset; + buf_size -= *buf_offset; + if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */ - (size > 27 && size < 1500) && /* normal sized MTU */ + (buf_size >= csum_size && buf_size < 1500) && /* normal sized MTU */ (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */ (buf[23] == 17) && /* ip.protocol == UDP */ (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */ - net_checksum_calculate(buf, size, CSUM_UDP); + memcpy((uint8_t *)hdr + *hdr_len, buf, csum_size); + net_checksum_calculate((uint8_t *)hdr + *hdr_len, csum_size, CSUM_UDP); hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM; + *hdr_len += csum_size; + *buf_offset += csum_size; } } -static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt, - const void *buf, size_t size) +static size_t receive_header(VirtIONet *n, struct virtio_net_hdr *hdr, + const void *buf, size_t buf_size, + size_t *buf_offset) { - if (n->has_vnet_hdr) { - /* FIXME this cast is evil */ - void *wbuf = (void *)buf; - work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, - size - n->host_hdr_len); + size_t hdr_len = n->guest_hdr_len; - if (n->needs_vnet_hdr_swap) { - virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf); - } - iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr)); - } else { - struct virtio_net_hdr hdr = { - .flags = 0, - .gso_type = VIRTIO_NET_HDR_GSO_NONE - }; - iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr); + memcpy(hdr, buf, sizeof(struct virtio_net_hdr)); + + *buf_offset = n->host_hdr_len; + work_around_broken_dhclient(hdr, &hdr_len, buf, buf_size, buf_offset); + + if (n->needs_vnet_hdr_swap) { + virtio_net_hdr_swap(VIRTIO_DEVICE(n), hdr); } + + return hdr_len; } static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) @@ -1894,33 +1900,42 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, return (index == new_index) ? -1 : new_index; } +typedef struct Header { + struct virtio_net_hdr_v1_hash virtio_net; + struct eth_header eth; + struct ip_header ip; + struct udp_header udp; +} Header; + static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, - size_t size, bool no_rss) + size_t size) { VirtIONet *n = qemu_get_nic_opaque(nc); - VirtIONetQueue *q = virtio_net_get_subqueue(nc); + VirtIONetQueue *q; VirtIODevice *vdev = VIRTIO_DEVICE(n); VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE]; size_t lens[VIRTQUEUE_MAX_SIZE]; struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; - struct virtio_net_hdr_v1_hash extra_hdr; + Header hdr; unsigned mhdr_cnt = 0; size_t offset, i, guest_offset, j; ssize_t err; - if (!virtio_net_can_receive(nc)) { - return -1; - } + memset(&hdr.virtio_net, 0, sizeof(hdr.virtio_net)); - if (!no_rss && n->rss_data.enabled && n->rss_data.enabled_software_rss) { - int index = virtio_net_process_rss(nc, buf, size, &extra_hdr); + if (n->rss_data.enabled && n->rss_data.enabled_software_rss) { + int index = virtio_net_process_rss(nc, buf, size, &hdr.virtio_net); if (index >= 0) { - NetClientState *nc2 = - qemu_get_subqueue(n->nic, index % n->curr_queue_pairs); - return virtio_net_receive_rcu(nc2, buf, size, true); + nc = qemu_get_subqueue(n->nic, index % n->curr_queue_pairs); } } + if (!virtio_net_can_receive(nc)) { + return -1; + } + + q = virtio_net_get_subqueue(nc); + /* hdr_len refers to the header we supply to the guest */ if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) { return 0; @@ -1974,21 +1989,18 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, if (n->mergeable_rx_bufs) { mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg), sg, elem->in_num, - offsetof(typeof(extra_hdr), hdr.num_buffers), - sizeof(extra_hdr.hdr.num_buffers)); + offsetof(typeof(hdr), + virtio_net.hdr.num_buffers), + sizeof(hdr.virtio_net.hdr.num_buffers)); } - receive_header(n, sg, elem->in_num, buf, size); - if (n->rss_data.populate_hash) { - offset = offsetof(typeof(extra_hdr), hash_value); - iov_from_buf(sg, elem->in_num, offset, - (char *)&extra_hdr + offset, - sizeof(extra_hdr.hash_value) + - sizeof(extra_hdr.hash_report)); - } - offset = n->host_hdr_len; - total += n->guest_hdr_len; - guest_offset = n->guest_hdr_len; + guest_offset = n->has_vnet_hdr ? + receive_header(n, (struct virtio_net_hdr *)&hdr, + buf, size, &offset) : + n->guest_hdr_len; + + iov_from_buf(sg, elem->in_num, 0, &hdr, guest_offset); + total += guest_offset; } else { guest_offset = 0; } @@ -2014,11 +2026,11 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, } if (mhdr_cnt) { - virtio_stw_p(vdev, &extra_hdr.hdr.num_buffers, i); + virtio_stw_p(vdev, &hdr.virtio_net.hdr.num_buffers, i); iov_from_buf(mhdr_sg, mhdr_cnt, 0, - &extra_hdr.hdr.num_buffers, - sizeof extra_hdr.hdr.num_buffers); + &hdr.virtio_net.hdr.num_buffers, + sizeof hdr.virtio_net.hdr.num_buffers); } for (j = 0; j < i; j++) { @@ -2046,7 +2058,22 @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, { RCU_READ_LOCK_GUARD(); - return virtio_net_receive_rcu(nc, buf, size, false); + return virtio_net_receive_rcu(nc, buf, size); +} + +/* + * Accessors to read and write the IP packet data length field. This + * is a potentially unaligned network-byte-order 16 bit unsigned integer + * pointed to by unit->ip_len. + */ +static uint16_t read_unit_ip_len(VirtioNetRscUnit *unit) +{ + return lduw_be_p(unit->ip_plen); +} + +static void write_unit_ip_len(VirtioNetRscUnit *unit, uint16_t l) +{ + stw_be_p(unit->ip_plen, l); } static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, @@ -2063,7 +2090,7 @@ static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, unit->ip_plen = &ip->ip_len; unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen); unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; - unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen; + unit->payload = read_unit_ip_len(unit) - ip_hdrlen - unit->tcp_hdrlen; } static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain, @@ -2082,7 +2109,7 @@ static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain, /* There is a difference between payload length in ipv4 and v6, ip header is excluded in ipv6 */ - unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen; + unit->payload = read_unit_ip_len(unit) - unit->tcp_hdrlen; } static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain, @@ -2231,7 +2258,7 @@ static int32_t virtio_net_rsc_coalesce_data(VirtioNetRscChain *chain, VirtioNetRscUnit *o_unit; o_unit = &seg->unit; - o_ip_len = htons(*o_unit->ip_plen); + o_ip_len = read_unit_ip_len(o_unit); nseq = htonl(n_unit->tcp->th_seq); oseq = htonl(o_unit->tcp->th_seq); @@ -2267,7 +2294,7 @@ coalesce: o_unit->payload += n_unit->payload; /* update new data len */ /* update field in ip header */ - *o_unit->ip_plen = htons(o_ip_len + n_unit->payload); + write_unit_ip_len(o_unit, o_ip_len + n_unit->payload); /* Bring 'PUSH' big, the whql test guide says 'PUSH' can be coalesced for windows guest, while this may change the behavior for linux @@ -3037,6 +3064,15 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) virtio_net_set_queue_pairs(n); } +static int virtio_net_pre_load_queues(VirtIODevice *vdev) +{ + virtio_net_set_multiqueue(VIRTIO_NET(vdev), + virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_RSS) || + virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_MQ)); + + return 0; +} + static int virtio_net_post_load_device(void *opaque, int version_id) { VirtIONet *n = opaque; @@ -4046,6 +4082,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO); + vdc->pre_load_queues = virtio_net_pre_load_queues; vdc->post_load = virtio_net_post_load_virtio; vdc->vmsd = &vmstate_virtio_net_device; vdc->primary_unplug_pending = primary_unplug_pending; diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 69bce20f66..ec75419566 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -656,6 +656,12 @@ static void nvme_irq_check(NvmeCtrl *n) if (msix_enabled(pci)) { return; } + + /* vfs does not implement intx */ + if (pci_is_vf(pci)) { + return; + } + if (~intms & n->irq_status) { pci_irq_assert(pci); } else { @@ -5423,7 +5429,7 @@ static void nvme_free_cq(NvmeCQueue *cq, NvmeCtrl *n) event_notifier_set_handler(&cq->notifier, NULL); event_notifier_cleanup(&cq->notifier); } - if (msix_enabled(pci)) { + if (msix_enabled(pci) && cq->irq_enabled) { msix_vector_unuse(pci, cq->vector); } if (cq->cqid) { @@ -5464,9 +5470,10 @@ static void nvme_init_cq(NvmeCQueue *cq, NvmeCtrl *n, uint64_t dma_addr, { PCIDevice *pci = PCI_DEVICE(n); - if (msix_enabled(pci)) { + if (msix_enabled(pci) && irq_enabled) { msix_vector_use(pci, vector); } + cq->ctrl = n; cq->cqid = cqid; cq->size = size; @@ -8543,7 +8550,7 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp) unsigned nr_vectors; int ret; - pci_conf[PCI_INTERRUPT_PIN] = 1; + pci_conf[PCI_INTERRUPT_PIN] = pci_is_vf(pci_dev) ? 0 : 1; pci_config_set_prog_interface(pci_conf, 0x2); if (n->params.use_intel_id) { @@ -8834,6 +8841,13 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) */ n->params.serial = g_strdup(pn->params.serial); n->subsys = pn->subsys; + + /* + * Assigning this link (strong link) causes an `object_unref` later in + * `object_release_link_property`. Increment the refcount to balance + * this out. + */ + object_ref(OBJECT(pn->subsys)); } if (!nvme_check_params(n, errp)) { @@ -8904,7 +8918,12 @@ static void nvme_exit(PCIDevice *pci_dev) pcie_sriov_pf_exit(pci_dev); } - msix_uninit(pci_dev, &n->bar0, &n->bar0); + if (n->params.msix_exclusive_bar && !pci_is_vf(pci_dev)) { + msix_uninit_exclusive_bar(pci_dev); + } else { + msix_uninit(pci_dev, &n->bar0, &n->bar0); + } + memory_region_del_subregion(&n->bar0, &n->iomem); } diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c index 1036d8600d..421c287eb0 100644 --- a/hw/pci-host/mv64361.c +++ b/hw/pci-host/mv64361.c @@ -95,6 +95,7 @@ static void mv64361_pcihost_realize(DeviceState *dev, Error **errp) &s->mem, &s->io, 0, 4, TYPE_PCI_BUS); g_free(name); pci_create_simple(h->bus, 0, TYPE_MV64361_PCI_BRIDGE); + qdev_init_gpio_out(dev, s->irq, ARRAY_SIZE(s->irq)); } static Property mv64361_pcihost_props[] = { diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 8ff4a00c34..16abeaac82 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -14,6 +14,7 @@ #include "hw/sysbus.h" #include "hw/pci/pci_host.h" #include "hw/irq.h" +#include "hw/or-irq.h" #include "hw/pci-host/mv64361.h" #include "hw/isa/vt82c686.h" #include "hw/ide/pci.h" @@ -73,8 +74,11 @@ OBJECT_DECLARE_TYPE(Pegasos2MachineState, MachineClass, PEGASOS2_MACHINE) struct Pegasos2MachineState { MachineState parent_obj; + PowerPCCPU *cpu; DeviceState *mv; + IRQState pci_irqs[PCI_NUM_PINS]; + OrIRQState orirq[PCI_NUM_PINS]; qemu_irq mv_pirq[PCI_NUM_PINS]; qemu_irq via_pirq[PCI_NUM_PINS]; Vof *vof; @@ -177,7 +181,6 @@ static void pegasos2_init(MachineState *machine) pm->mv_pirq[i] = qdev_get_gpio_in_named(pm->mv, "gpp", 12 + i); } pci_bus = mv64361_get_pci_bus(pm->mv, 1); - pci_bus_irqs(pci_bus, pegasos2_pci_irq, pm, PCI_NUM_PINS); /* VIA VT8231 South Bridge (multifunction PCI device) */ via = OBJECT(pci_new_multifunction(PCI_DEVFN(12, 0), TYPE_VT8231_ISA)); @@ -209,6 +212,31 @@ static void pegasos2_init(MachineState *machine) /* other PC hardware */ pci_vga_init(pci_bus); + /* PCI interrupt routing: lines from pci.0 and pci.1 are ORed */ + for (int h = 0; h < 2; h++) { + DeviceState *pd; + g_autofree const char *pn = g_strdup_printf("pcihost%d", h); + + pd = DEVICE(object_resolve_path_component(OBJECT(pm->mv), pn)); + assert(pd); + for (i = 0; i < PCI_NUM_PINS; i++) { + OrIRQState *ori = &pm->orirq[i]; + + if (h == 0) { + g_autofree const char *n = g_strdup_printf("pci-orirq[%d]", i); + + object_initialize_child_with_props(OBJECT(pm), n, + ori, sizeof(*ori), + TYPE_OR_IRQ, &error_fatal, + "num-lines", "2", NULL); + qdev_realize(DEVICE(ori), NULL, &error_fatal); + qemu_init_irq(&pm->pci_irqs[i], pegasos2_pci_irq, pm, i); + qdev_connect_gpio_out(DEVICE(ori), 0, &pm->pci_irqs[i]); + } + qdev_connect_gpio_out(pd, i, qdev_get_gpio_in(DEVICE(ori), h)); + } + } + if (machine->kernel_filename) { sz = load_elf(machine->kernel_filename, NULL, NULL, NULL, &pm->kernel_entry, &pm->kernel_addr, NULL, NULL, 1, diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index a30693990b..e6b02294b1 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -217,8 +217,8 @@ static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr, case PNV10_XSCOM_EC_CORE_RAS_STATUS: for (i = 0; i < nr_threads; i++) { PowerPCCPU *cpu = pc->threads[i]; - CPUState *cs = CPU(cpu); - if (cs->stopped) { + CPUPPCState *env = &cpu->env; + if (env->quiesced) { val |= PPC_BIT(0 + 8 * i) | PPC_BIT(1 + 8 * i); } } @@ -244,20 +244,25 @@ static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr, for (i = 0; i < nr_threads; i++) { PowerPCCPU *cpu = pc->threads[i]; CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; if (val & PPC_BIT(7 + 8 * i)) { /* stop */ val &= ~PPC_BIT(7 + 8 * i); cpu_pause(cs); + env->quiesced = true; } if (val & PPC_BIT(6 + 8 * i)) { /* start */ val &= ~PPC_BIT(6 + 8 * i); + env->quiesced = false; cpu_resume(cs); } if (val & PPC_BIT(4 + 8 * i)) { /* sreset */ val &= ~PPC_BIT(4 + 8 * i); + env->quiesced = false; pnv_cpu_do_nmi_resume(cs); } if (val & PPC_BIT(3 + 8 * i)) { /* clear maint */ + env->quiesced = false; /* * Hardware has very particular cases for where clear maint * must be used and where start must be used to resume a @@ -317,6 +322,8 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp, pir_spr->default_value = pir; tir_spr->default_value = tir; + env->chip_index = pc->chip->chip_id; + if (pc->big_core) { /* 2 "small cores" get the same core index for SMT operations */ env->core_index = core_hwid >> 1; diff --git a/hw/ppc/pnv_nest_pervasive.c b/hw/ppc/pnv_nest_pervasive.c index 77476753a4..780fa69dde 100644 --- a/hw/ppc/pnv_nest_pervasive.c +++ b/hw/ppc/pnv_nest_pervasive.c @@ -177,7 +177,7 @@ static void pnv_nest_pervasive_realize(DeviceState *dev, Error **errp) pnv_xscom_region_init(&nest_pervasive->xscom_ctrl_regs_mr, OBJECT(nest_pervasive), &pnv_nest_pervasive_control_xscom_ops, - nest_pervasive, "pervasive-control", + nest_pervasive, "xscom-pervasive-control", PNV10_XSCOM_CHIPLET_CTRL_REGS_SIZE); } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 5c02037c56..0d4efaa0c0 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -701,7 +701,7 @@ static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset, uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ]; int i; - drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index); + drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, env->core_index); if (drc) { drc_index = spapr_drc_index(drc); _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index))); diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index ada439e831..135f86a622 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -313,6 +313,7 @@ static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp) return NULL; } + env->chip_index = sc->node_id; env->core_index = cc->core_id; cpu->node_id = sc->node_id; diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c index 230cc09e03..30f2fb486f 100644 --- a/hw/s390x/ccw-device.c +++ b/hw/s390x/ccw-device.c @@ -73,7 +73,7 @@ static void ccw_device_set_loadparm(Object *obj, Visitor *v, s390_ipl_fmt_loadparm(dev->loadparm, val, errp); } -static const PropertyInfo ccw_loadparm = { +const PropertyInfo ccw_loadparm = { .name = "ccw_loadparm", .description = "Up to 8 chars in set of [A-Za-z0-9. ] to pass" " to the guest loader/kernel", @@ -85,8 +85,6 @@ static Property ccw_device_properties[] = { DEFINE_PROP_CSS_DEV_ID("devno", CcwDevice, devno), DEFINE_PROP_CSS_DEV_ID_RO("dev_id", CcwDevice, dev_id), DEFINE_PROP_CSS_DEV_ID_RO("subch_id", CcwDevice, subch_id), - DEFINE_PROP("loadparm", CcwDevice, loadparm, ccw_loadparm, - typeof(uint8_t[8])), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390x/ccw-device.h b/hw/s390x/ccw-device.h index 1e1737c0f3..4439feb140 100644 --- a/hw/s390x/ccw-device.h +++ b/hw/s390x/ccw-device.h @@ -51,4 +51,9 @@ static inline CcwDevice *to_ccw_dev_fast(DeviceState *d) OBJECT_DECLARE_TYPE(CcwDevice, CCWDeviceClass, CCW_DEVICE) +extern const PropertyInfo ccw_loadparm; + +#define DEFINE_PROP_CCW_LOADPARM(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, ccw_loadparm, typeof(uint8_t[8])) + #endif diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index dc02b0fdda..30734661ad 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -418,21 +418,9 @@ static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain) void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp) { - int i; - /* Initialize the loadparm with spaces */ memset(loadparm, ' ', LOADPARM_LEN); - for (i = 0; i < LOADPARM_LEN && str[i]; i++) { - uint8_t c = qemu_toupper(str[i]); /* mimic HMC */ - - if (qemu_isalnum(c) || c == '.' || c == ' ') { - loadparm[i] = c; - } else { - error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)", - c, c); - return; - } - } + qdev_prop_sanitize_s390x_loadparm(loadparm, str, errp); } void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp) @@ -452,6 +440,7 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb) SCSIDevice *sd; int devtype; uint8_t *lp; + g_autofree void *scsi_lp = NULL; /* * Currently allow IPL only from CCW devices. @@ -463,6 +452,10 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb) switch (devtype) { case CCW_DEVTYPE_SCSI: sd = SCSI_DEVICE(dev_st); + scsi_lp = object_property_get_str(OBJECT(sd), "loadparm", NULL); + if (scsi_lp && strlen(scsi_lp) > 0) { + lp = scsi_lp; + } iplb->len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN); iplb->blk0_len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN); diff --git a/hw/s390x/virtio-ccw-blk.c b/hw/s390x/virtio-ccw-blk.c index 8e0e58b77d..2364432c6e 100644 --- a/hw/s390x/virtio-ccw-blk.c +++ b/hw/s390x/virtio-ccw-blk.c @@ -48,6 +48,7 @@ static Property virtio_ccw_blk_properties[] = { VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, VIRTIO_CCW_MAX_REV), + DEFINE_PROP_CCW_LOADPARM("loadparm", CcwDevice, loadparm), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390x/virtio-ccw-net.c b/hw/s390x/virtio-ccw-net.c index 484e617659..a4a3f65c7e 100644 --- a/hw/s390x/virtio-ccw-net.c +++ b/hw/s390x/virtio-ccw-net.c @@ -51,6 +51,7 @@ static Property virtio_ccw_net_properties[] = { VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, VIRTIO_CCW_MAX_REV), + DEFINE_PROP_CCW_LOADPARM("loadparm", CcwDevice, loadparm), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 221b06d6aa..b33229d71a 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -1781,7 +1781,7 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) uint8_t cdb[16]; int len; struct SCSIDevice *sdev = NULL; - int target_id, lun_id, cdb_len; + int target_id, lun_id; lba_count = le32_to_cpu(cmd->frame->io.header.data_len); lba_start_lo = le32_to_cpu(cmd->frame->io.lba_lo); @@ -1790,7 +1790,6 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) target_id = cmd->frame->header.target_id; lun_id = cmd->frame->header.lun_id; - cdb_len = cmd->frame->header.cdb_len; if (target_id < MFI_MAX_LD && lun_id == 0) { sdev = scsi_device_find(&s->bus, 0, target_id, lun_id); @@ -1805,15 +1804,6 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) return MFI_STAT_DEVICE_NOT_FOUND; } - if (cdb_len > 16) { - trace_megasas_scsi_invalid_cdb_len( - mfi_frame_desc(frame_cmd), 1, target_id, lun_id, cdb_len); - megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE)); - cmd->frame->header.scsi_status = CHECK_CONDITION; - s->event_count++; - return MFI_STAT_SCSI_DONE_WITH_ERROR; - } - cmd->iov_size = lba_count * sdev->blocksize; if (megasas_map_sgl(s, cmd, &cmd->frame->io.sgl)) { megasas_write_sense(cmd, SENSE_CODE(TARGET_FAILURE)); @@ -1824,7 +1814,7 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) megasas_encode_lba(cdb, lba_start, lba_count, is_write); cmd->req = scsi_req_new(sdev, cmd->index, - lun_id, cdb, cdb_len, cmd); + lun_id, cdb, sizeof(cdb), cmd); if (!cmd->req) { trace_megasas_scsi_req_alloc_failed( mfi_frame_desc(frame_cmd), target_id, lun_id); diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index cb222da7a5..7f13b0588f 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -32,6 +32,7 @@ #include "migration/vmstate.h" #include "hw/scsi/emulation.h" #include "scsi/constants.h" +#include "sysemu/arch_init.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "hw/block/block.h" @@ -111,6 +112,7 @@ struct SCSIDiskState { char *vendor; char *product; char *device_id; + char *loadparm; /* only for s390x */ bool tray_open; bool tray_locked; /* @@ -3135,6 +3137,43 @@ BlockAIOCB *scsi_dma_writev(int64_t offset, QEMUIOVector *iov, return blk_aio_pwritev(s->qdev.conf.blk, offset, iov, 0, cb, cb_opaque); } +static char *scsi_property_get_loadparm(Object *obj, Error **errp) +{ + return g_strdup(SCSI_DISK_BASE(obj)->loadparm); +} + +static void scsi_property_set_loadparm(Object *obj, const char *value, + Error **errp) +{ + void *lp_str; + + if (object_property_get_int(obj, "bootindex", NULL) < 0) { + error_setg(errp, "'loadparm' is only valid for boot devices"); + return; + } + + lp_str = g_malloc0(strlen(value) + 1); + if (!qdev_prop_sanitize_s390x_loadparm(lp_str, value, errp)) { + g_free(lp_str); + return; + } + SCSI_DISK_BASE(obj)->loadparm = lp_str; +} + +static void scsi_property_add_specifics(DeviceClass *dc) +{ + ObjectClass *oc = OBJECT_CLASS(dc); + + /* The loadparm property is only supported on s390x */ + if (arch_type & QEMU_ARCH_S390X) { + object_class_property_add_str(oc, "loadparm", + scsi_property_get_loadparm, + scsi_property_set_loadparm); + object_class_property_set_description(oc, "loadparm", + "load parameter (s390x only)"); + } +} + static void scsi_disk_base_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -3218,6 +3257,8 @@ static void scsi_hd_class_initfn(ObjectClass *klass, void *data) dc->desc = "virtual SCSI disk"; device_class_set_props(dc, scsi_hd_properties); dc->vmsd = &vmstate_scsi_disk_state; + + scsi_property_add_specifics(dc); } static const TypeInfo scsi_hd_info = { @@ -3258,6 +3299,8 @@ static void scsi_cd_class_initfn(ObjectClass *klass, void *data) dc->desc = "virtual SCSI CD-ROM"; device_class_set_props(dc, scsi_cd_properties); dc->vmsd = &vmstate_scsi_disk_state; + + scsi_property_add_specifics(dc); } static const TypeInfo scsi_cd_info = { diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index dbe5c2340c..37875c02c3 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -233,7 +233,7 @@ static void sdhci_raise_insertion_irq(void *opaque) if (s->norintsts & SDHC_NIS_REMOVE) { timer_mod(s->insert_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY); + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY); } else { s->prnsts = 0x1ff0000; if (s->norintstsen & SDHC_NISEN_INSERT) { @@ -251,7 +251,7 @@ static void sdhci_set_inserted(DeviceState *dev, bool level) if ((s->norintsts & SDHC_NIS_REMOVE) && level) { /* Give target some time to notice card ejection */ timer_mod(s->insert_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY); + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY); } else { if (level) { s->prnsts = 0x1ff0000; @@ -289,9 +289,11 @@ static void sdhci_reset(SDHCIState *s) timer_del(s->insert_timer); timer_del(s->transfer_timer); - /* Set all registers to 0. Capabilities/Version registers are not cleared + /* + * Set all registers to 0. Capabilities/Version registers are not cleared * and assumed to always preserve their value, given to them during - * initialization */ + * initialization + */ memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad); /* Reset other state based on current card insertion/readonly status */ @@ -305,7 +307,8 @@ static void sdhci_reset(SDHCIState *s) static void sdhci_poweron_reset(DeviceState *dev) { - /* QOM (ie power-on) reset. This is identical to reset + /* + * QOM (ie power-on) reset. This is identical to reset * commanded via device register apart from handling of the * 'pending insert on powerup' quirk. */ @@ -445,8 +448,10 @@ static void sdhci_read_block_from_card(SDHCIState *s) s->prnsts &= ~SDHC_DAT_LINE_ACTIVE; } - /* If stop at block gap request was set and it's not the last block of - * data - generate Block Event interrupt */ + /* + * If stop at block gap request was set and it's not the last block of + * data - generate Block Event interrupt + */ if (s->stopped_state == sdhc_gap_read && (s->trnmod & SDHC_TRNS_MULTI) && s->blkcnt != 1) { s->prnsts &= ~SDHC_DAT_LINE_ACTIVE; @@ -548,8 +553,10 @@ static void sdhci_write_block_to_card(SDHCIState *s) sdhci_update_irq(s); } -/* Write @size bytes of @value data to host controller @s Buffer Data Port - * register */ +/* + * Write @size bytes of @value data to host controller @s Buffer Data Port + * register + */ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size) { unsigned i; @@ -594,9 +601,11 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) return; } - /* XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for + /* + * XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for * possible stop at page boundary if initial address is not page aligned, - * allow them to work properly */ + * allow them to work properly + */ if ((s->sdmasysad % boundary_chk) == 0) { page_aligned = true; } @@ -702,7 +711,8 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr) dma_memory_read(s->dma_as, entry_addr, &adma2, sizeof(adma2), MEMTXATTRS_UNSPECIFIED); adma2 = le64_to_cpu(adma2); - /* The spec does not specify endianness of descriptor table. + /* + * The spec does not specify endianness of descriptor table. * We currently assume that it is LE. */ dscr->addr = (hwaddr)extract64(adma2, 32, 32) & ~0x3ull; @@ -977,8 +987,10 @@ static bool sdhci_can_issue_command(SDHCIState *s) return true; } -/* The Buffer Data Port register must be accessed in sequential and - * continuous manner */ +/* + * The Buffer Data Port register must be accessed in sequential and + * continuous manner + */ static inline bool sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num) { @@ -1206,8 +1218,10 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) MASKED_WRITE(s->argument, mask, value); break; case SDHC_TRNMOD: - /* DMA can be enabled only if it is supported as indicated by - * capabilities register */ + /* + * DMA can be enabled only if it is supported as indicated by + * capabilities register + */ if (!(s->capareg & R_SDHC_CAPAB_SDMA_MASK)) { value &= ~SDHC_TRNS_DMA; } @@ -1279,8 +1293,10 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) } else { s->norintsts &= ~SDHC_NIS_ERR; } - /* Quirk for Raspberry Pi: pending card insert interrupt - * appears when first enabled after power on */ + /* + * Quirk for Raspberry Pi: pending card insert interrupt + * appears when first enabled after power on + */ if ((s->norintstsen & SDHC_NISEN_INSERT) && s->pending_insert_state) { assert(s->pending_insert_quirk); s->norintsts |= SDHC_NIS_INSERT; @@ -1396,8 +1412,10 @@ void sdhci_initfn(SDHCIState *s) { qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SDHCI_BUS, DEVICE(s), "sd-bus"); - s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s); - s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s); + s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + sdhci_raise_insertion_irq, s); + s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + sdhci_data_transfer, s); s->io_ops = &sdhci_mmio_le_ops; } @@ -1445,11 +1463,13 @@ void sdhci_common_realize(SDHCIState *s, Error **errp) void sdhci_common_unrealize(SDHCIState *s) { - /* This function is expected to be called only once for each class: + /* + * This function is expected to be called only once for each class: * - SysBus: via DeviceClass->unrealize(), * - PCI: via PCIDeviceClass->exit(). * However to avoid double-free and/or use-after-free we still nullify - * this variable (better safe than sorry!). */ + * this variable (better safe than sorry!). + */ g_free(s->fifo_buffer); s->fifo_buffer = NULL; } diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index e807fe2de9..5c6e139b20 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -815,7 +815,7 @@ static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s) /* Both are counting */ icnto = remain / s->tcntb; if (icnto) { - tcnto = remain % (icnto * s->tcntb); + tcnto = remain % ((uint64_t)icnto * s->tcntb); } else { tcnto = remain % s->tcntb; } diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 06e9537d03..2c3640c705 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -479,6 +479,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p, usb_hub_port_clear(port, PORT_STAT_SUSPEND); port->wPortChange = 0; } + break; default: goto fail; } diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 24703c814a..c1cd7736cd 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -662,6 +662,7 @@ static Property vfio_ccw_properties[] = { DEFINE_PROP_LINK("iommufd", VFIOCCWDevice, vdev.iommufd, TYPE_IOMMUFD_BACKEND, IOMMUFDBackend *), #endif + DEFINE_PROP_CCW_LOADPARM("loadparm", CcwDevice, loadparm), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index 809b157674..6f86c37d97 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -103,7 +103,7 @@ static void vfio_container_instance_finalize(Object *obj) VFIOContainerBase *bcontainer = VFIO_IOMMU(obj); VFIOGuestIOMMU *giommu, *tmp; - QLIST_REMOVE(bcontainer, next); + QLIST_SAFE_REMOVE(bcontainer, next); QLIST_FOREACH_SAFE(giommu, &bcontainer->giommu_list, giommu_next, tmp) { memory_region_unregister_iommu_notifier( diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c index a95d441f68..4047f4f071 100644 --- a/hw/vfio/igd.c +++ b/hw/vfio/igd.c @@ -88,6 +88,9 @@ static int igd_gen(VFIOPCIDevice *vdev) case 0x2200: case 0x5900: return 8; + /* CoffeeLake */ + case 0x3e00: + return 9; /* ElkhartLake */ case 0x4500: return 11; @@ -498,7 +501,7 @@ static int igd_get_stolen_mb(int gen, uint32_t gmch) if (gms < 0xf0) return gms * 32; else - return gms * 4 + 4; + return (gms - 0xf0) * 4 + 4; } } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 76f9b2aaad..c40f48ac4d 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -2095,11 +2095,22 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) * vhost-kernel code requires for this.*/ for (i = 0; i < hdev->nvqs; ++i) { struct vhost_virtqueue *vq = hdev->vqs + i; - vhost_device_iotlb_miss(hdev, vq->used_phys, true); + r = vhost_device_iotlb_miss(hdev, vq->used_phys, true); + if (r) { + goto fail_iotlb; + } } } vhost_start_config_intr(hdev); return 0; +fail_iotlb: + if (vhost_dev_has_iommu(hdev) && + hdev->vhost_ops->vhost_set_iotlb_callback) { + hdev->vhost_ops->vhost_set_iotlb_callback(hdev, false); + } + if (hdev->vhost_ops->vhost_dev_start) { + hdev->vhost_ops->vhost_dev_start(hdev, false); + } fail_start: if (vrings) { vhost_dev_set_vring_enable(hdev, false); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index a26f18908e..f12c4aa81e 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3255,6 +3255,13 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) config_len--; } + if (vdc->pre_load_queues) { + ret = vdc->pre_load_queues(vdev); + if (ret) { + return ret; + } + } + num = qemu_get_be32(f); if (num > VIRTIO_QUEUE_MAX) { diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c index 7ad46f9410..ed5ff4257c 100644 --- a/hw/watchdog/cmsdk-apb-watchdog.c +++ b/hw/watchdog/cmsdk-apb-watchdog.c @@ -12,8 +12,8 @@ /* * This is a model of the "APB watchdog" which is part of the Cortex-M * System Design Kit (CMSDK) and documented in the Cortex-M System - * Design Kit Technical Reference Manual (ARM DDI0479C): - * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit + * Design Kit Technical Reference Manual (ARM DDI0479): + * https://developer.arm.com/documentation/ddi0479/ * * We also support the variant of this device found in the TI * Stellaris/Luminary boards and documented in: @@ -196,16 +196,13 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset, switch (offset) { case A_WDOGLOAD: - /* - * Reset the load value and the current count, and make sure - * we're counting. - */ + /* Reset the load value and the current count. */ ptimer_transaction_begin(s->timer); ptimer_set_limit(s->timer, value, 1); - ptimer_run(s->timer, 0); ptimer_transaction_commit(s->timer); break; - case A_WDOGCONTROL: + case A_WDOGCONTROL: { + uint32_t prev_control = s->control; if (s->is_luminary && 0 != (R_WDOGCONTROL_INTEN_MASK & s->control)) { /* * The Luminary version of this device ignores writes to @@ -215,8 +212,25 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset, break; } s->control = value & R_WDOGCONTROL_VALID_MASK; + if (R_WDOGCONTROL_INTEN_MASK & (s->control ^ prev_control)) { + ptimer_transaction_begin(s->timer); + if (R_WDOGCONTROL_INTEN_MASK & s->control) { + /* + * Set HIGH to enable the counter and the interrupt. Reloads + * the counter from the value in WDOGLOAD when the interrupt + * is enabled, after previously being disabled. + */ + ptimer_set_count(s->timer, ptimer_get_limit(s->timer)); + ptimer_run(s->timer, 0); + } else { + /* Or LOW to disable the counter and interrupt. */ + ptimer_stop(s->timer); + } + ptimer_transaction_commit(s->timer); + } cmsdk_apb_watchdog_update(s); break; + } case A_WDOGINTCLR: s->intstatus = 0; ptimer_transaction_begin(s->timer); @@ -305,8 +319,14 @@ static void cmsdk_apb_watchdog_reset(DeviceState *dev) s->resetstatus = 0; /* Set the limit and the count */ ptimer_transaction_begin(s->timer); + /* + * We need to stop the ptimer before setting its limit reset value. If the + * order is the opposite when the code executes the stop after setting a new + * limit it may want to recalculate the count based on the current time (if + * the timer was currently running) and it won't get the proper reset value. + */ + ptimer_stop(s->timer); ptimer_set_limit(s->timer, 0xffffffff, 1); - ptimer_run(s->timer, 0); ptimer_transaction_commit(s->timer); } diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index db8a6fbc6e..c3ca0babcb 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -158,8 +158,6 @@ struct CPUClass { void (*dump_state)(CPUState *cpu, FILE *, int flags); void (*query_cpu_fast)(CPUState *cpu, CpuInfoFast *value); int64_t (*get_arch_id)(CPUState *cpu); - bool (*cpu_persistent_status)(CPUState *cpu); - bool (*cpu_enabled_status)(CPUState *cpu); void (*set_pc)(CPUState *cpu, vaddr value); vaddr (*get_pc)(CPUState *cpu); int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg); diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h index cd09bee3bc..a3d6a0e507 100644 --- a/include/hw/intc/arm_gicv3_common.h +++ b/include/hw/intc/arm_gicv3_common.h @@ -51,13 +51,13 @@ /* Maximum number of list registers (architectural limit) */ #define GICV3_LR_MAX 16 -/* For some distributor fields we want to model the array of 32-bit +/* + * For some distributor fields we want to model the array of 32-bit * register values which hold various bitmaps corresponding to enabled, - * pending, etc bits. These macros and functions facilitate that; the - * APIs are generally modelled on the generic bitmap.h functions - * (which are unsuitable here because they use 'unsigned long' as the - * underlying storage type, which is very awkward when you need to - * access the data as 32-bit values.) + * pending, etc bits. We use the set_bit32() etc family of functions + * from bitops.h for this. For a few cases we need to implement some + * extra operations. + * * Each bitmap contains a bit for each interrupt. Although there is * space for the PPIs and SGIs, those bits (the first 32) are never * used as that state lives in the redistributor. The unused bits are @@ -65,39 +65,13 @@ * avoids bugs where we forget to subtract GIC_INTERNAL from an * interrupt number. */ -#define GICV3_BMP_SIZE DIV_ROUND_UP(GICV3_MAXIRQ, 32) - -#define GIC_DECLARE_BITMAP(name) \ - uint32_t name[GICV3_BMP_SIZE] - -#define GIC_BIT_MASK(nr) (1U << ((nr) % 32)) -#define GIC_BIT_WORD(nr) ((nr) / 32) - -static inline void gic_bmp_set_bit(int nr, uint32_t *addr) -{ - uint32_t mask = GIC_BIT_MASK(nr); - uint32_t *p = addr + GIC_BIT_WORD(nr); - - *p |= mask; -} - -static inline void gic_bmp_clear_bit(int nr, uint32_t *addr) -{ - uint32_t mask = GIC_BIT_MASK(nr); - uint32_t *p = addr + GIC_BIT_WORD(nr); - - *p &= ~mask; -} - -static inline int gic_bmp_test_bit(int nr, const uint32_t *addr) -{ - return 1U & (addr[GIC_BIT_WORD(nr)] >> (nr & 31)); -} +#define GIC_DECLARE_BITMAP(name) DECLARE_BITMAP32(name, GICV3_MAXIRQ) +#define GICV3_BMP_SIZE BITS_TO_U32S(GICV3_MAXIRQ) static inline void gic_bmp_replace_bit(int nr, uint32_t *addr, int val) { - uint32_t mask = GIC_BIT_MASK(nr); - uint32_t *p = addr + GIC_BIT_WORD(nr); + uint32_t mask = BIT32_MASK(nr); + uint32_t *p = addr + BIT32_WORD(nr); *p &= ~mask; *p |= (val & 1U) << (nr % 32); @@ -106,7 +80,7 @@ static inline void gic_bmp_replace_bit(int nr, uint32_t *addr, int val) /* Return a pointer to the 32-bit word containing the specified bit. */ static inline uint32_t *gic_bmp_ptr32(uint32_t *addr, int nr) { - return addr + GIC_BIT_WORD(nr); + return addr + BIT32_WORD(nr); } typedef struct GICv3State GICv3State; @@ -301,15 +275,15 @@ struct GICv3State { #define GICV3_BITMAP_ACCESSORS(BMP) \ static inline void gicv3_gicd_##BMP##_set(GICv3State *s, int irq) \ { \ - gic_bmp_set_bit(irq, s->BMP); \ + set_bit32(irq, s->BMP); \ } \ static inline int gicv3_gicd_##BMP##_test(GICv3State *s, int irq) \ { \ - return gic_bmp_test_bit(irq, s->BMP); \ + return test_bit32(irq, s->BMP); \ } \ static inline void gicv3_gicd_##BMP##_clear(GICv3State *s, int irq) \ { \ - gic_bmp_clear_bit(irq, s->BMP); \ + clear_bit32(irq, s->BMP); \ } \ static inline void gicv3_gicd_##BMP##_replace(GICv3State *s, \ int irq, int value) \ diff --git a/include/hw/misc/mos6522.h b/include/hw/misc/mos6522.h index fba45668ab..920871a598 100644 --- a/include/hw/misc/mos6522.h +++ b/include/hw/misc/mos6522.h @@ -154,7 +154,7 @@ struct MOS6522State { OBJECT_DECLARE_TYPE(MOS6522State, MOS6522DeviceClass, MOS6522) struct MOS6522DeviceClass { - DeviceClass parent_class; + SysBusDeviceClass parent_class; ResettablePhases parent_phases; void (*portB_write)(MOS6522State *dev); diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 135695c551..c0717e3121 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -670,16 +670,6 @@ static inline void pci_irq_deassert(PCIDevice *pci_dev) pci_set_irq(pci_dev, 0); } -/* - * FIXME: PCI does not work this way. - * All the callers to this method should be fixed. - */ -static inline void pci_irq_pulse(PCIDevice *pci_dev) -{ - pci_irq_assert(pci_dev); - pci_irq_deassert(pci_dev); -} - MSIMessage pci_get_msi_message(PCIDevice *dev, int vector); void pci_set_power(PCIDevice *pci_dev, bool state); diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h index cdcc63056e..7ec37f6316 100644 --- a/include/hw/qdev-properties-system.h +++ b/include/hw/qdev-properties-system.h @@ -3,6 +3,9 @@ #include "hw/qdev-properties.h" +bool qdev_prop_sanitize_s390x_loadparm(uint8_t *loadparm, const char *str, + Error **errp); + extern const PropertyInfo qdev_prop_chr; extern const PropertyInfo qdev_prop_macaddr; extern const PropertyInfo qdev_prop_reserved_region; diff --git a/include/hw/usb/dwc2-regs.h b/include/hw/usb/dwc2-regs.h index 523b112c5e..b8b4266543 100644 --- a/include/hw/usb/dwc2-regs.h +++ b/include/hw/usb/dwc2-regs.h @@ -838,7 +838,7 @@ struct dwc2_dma_desc { uint32_t status; uint32_t buf; -} __packed; +} QEMU_PACKED; /* Host Mode DMA descriptor status quadlet */ diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 553799b8cc..8c977beebd 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -333,6 +333,21 @@ void virtio_gpu_update_cursor_data(VirtIOGPU *g, struct virtio_gpu_scanout *s, uint32_t resource_id); +/** + * virtio_gpu_scanout_blob_to_fb() - fill out fb based on scanout data + * fb: the frame-buffer descriptor to fill out + * ss: the scanout blob data + * blob_size: size of scanout blob data + * + * This will check we have enough space for the frame taking into + * account that stride. + * + * Returns true on success, otherwise logs guest error and returns false + */ +bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb, + struct virtio_gpu_set_scanout_blob *ss, + uint64_t blob_size); + /* virtio-gpu-udmabuf.c */ bool virtio_gpu_have_udmabuf(void); void virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res); diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 060c23c04d..b9ea9e824e 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -102,7 +102,7 @@ typedef struct VirtioNetRscStat { /* Rsc unit general info used to checking if can coalescing */ typedef struct VirtioNetRscUnit { void *ip; /* ip header */ - uint16_t *ip_plen; /* data len pointer in ip header field */ + void *ip_plen; /* pointer to unaligned uint16_t data len in ip header */ struct tcp_header *tcp; /* tcp header */ uint16_t tcp_hdrlen; /* tcp header len */ uint16_t payload; /* pure payload without virtio/eth/ip/tcp */ diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index f526ecc8fc..6386910280 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -210,6 +210,8 @@ struct VirtioDeviceClass { void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask); int (*start_ioeventfd)(VirtIODevice *vdev); void (*stop_ioeventfd)(VirtIODevice *vdev); + /* Called before loading queues. Useful to add queues before loading. */ + int (*pre_load_queues)(VirtIODevice *vdev); /* Saving and loading of a device; trying to deprecate save/load * use vmsd for new devices. */ diff --git a/include/net/checksum.h b/include/net/checksum.h index 7dec37e56c..188e4cca0b 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h @@ -30,7 +30,7 @@ uint32_t net_checksum_add_cont(int len, uint8_t *buf, int seq); uint16_t net_checksum_finish(uint32_t sum); uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, uint8_t *addrs, uint8_t *buf); -void net_checksum_calculate(uint8_t *data, int length, int csum_flag); +void net_checksum_calculate(void *data, int length, int csum_flag); static inline uint32_t net_checksum_add(int len, uint8_t *buf) diff --git a/include/net/eth.h b/include/net/eth.h index 3b80b6e07f..14c34f530f 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -56,7 +56,7 @@ struct ip_header { uint8_t ip_p; /* protocol */ uint16_t ip_sum; /* checksum */ uint32_t ip_src, ip_dst; /* source and destination address */ -}; +} QEMU_PACKED; typedef struct tcp_header { uint16_t th_sport; /* source port */ diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index 1cf288445f..0044333cb5 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -69,6 +69,14 @@ #define DECLARE_BITMAP(name,bits) \ unsigned long name[BITS_TO_LONGS(bits)] +/* + * This is for use with the bit32 versions of set_bit() etc; + * we don't currently support the full range of bitmap operations + * on bitmaps backed by an array of uint32_t. + */ +#define DECLARE_BITMAP32(name, bits) \ + uint32_t name[BITS_TO_U32S(bits)] + #define small_nbits(nbits) \ ((nbits) <= BITS_PER_LONG) diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index 2c0a2fe751..c7b838a628 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -18,17 +18,48 @@ #define BITS_PER_BYTE CHAR_BIT #define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) +#define BITS_TO_U32S(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(uint32_t)) #define BIT(nr) (1UL << (nr)) #define BIT_ULL(nr) (1ULL << (nr)) -#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define MAKE_64BIT_MASK(shift, length) \ (((~0ULL) >> (64 - (length))) << (shift)) /** + * DOC: Functions operating on arrays of bits + * + * We provide a set of functions which work on arbitrary-length arrays of + * bits. These come in several flavours which vary in what the type of the + * underlying storage for the bits is: + * + * - Bits stored in an array of 'unsigned long': set_bit(), clear_bit(), etc + * - Bits stored in an array of 'uint32_t': set_bit32(), clear_bit32(), etc + * + * Because the 'unsigned long' type has a size which varies between + * host systems, the versions using 'uint32_t' are often preferable. + * This is particularly the case in a device model where there may + * be some guest-visible register view of the bit array. + * + * We do not currently implement uint32_t versions of find_last_bit(), + * find_next_bit(), find_next_zero_bit(), find_first_bit() or + * find_first_zero_bit(), because we haven't yet needed them. If you + * need them you should implement them similarly to the 'unsigned long' + * versions. + * + * You can declare a bitmap to be used with these functions via the + * DECLARE_BITMAP and DECLARE_BITMAP32 macros in bitmap.h. + */ + +/** + * DOC: 'unsigned long' bit array APIs + */ + +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) + +/** * set_bit - Set a bit in memory * @nr: the bit to set * @addr: the address to start counting from @@ -225,6 +256,141 @@ static inline unsigned long find_first_zero_bit(const unsigned long *addr, } /** + * DOC: 'uint32_t' bit array APIs + */ + +#define BIT32_MASK(nr) (1UL << ((nr) % 32)) +#define BIT32_WORD(nr) ((nr) / 32) + +/** + * set_bit32 - Set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + */ +static inline void set_bit32(long nr, uint32_t *addr) +{ + uint32_t mask = BIT32_MASK(nr); + uint32_t *p = addr + BIT32_WORD(nr); + + *p |= mask; +} + +/** + * set_bit32_atomic - Set a bit in memory atomically + * @nr: the bit to set + * @addr: the address to start counting from + */ +static inline void set_bit32_atomic(long nr, uint32_t *addr) +{ + uint32_t mask = BIT32_MASK(nr); + uint32_t *p = addr + BIT32_WORD(nr); + + qatomic_or(p, mask); +} + +/** + * clear_bit32 - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + */ +static inline void clear_bit32(long nr, uint32_t *addr) +{ + uint32_t mask = BIT32_MASK(nr); + uint32_t *p = addr + BIT32_WORD(nr); + + *p &= ~mask; +} + +/** + * clear_bit32_atomic - Clears a bit in memory atomically + * @nr: Bit to clear + * @addr: Address to start counting from + */ +static inline void clear_bit32_atomic(long nr, uint32_t *addr) +{ + uint32_t mask = BIT32_MASK(nr); + uint32_t *p = addr + BIT32_WORD(nr); + + return qatomic_and(p, ~mask); +} + +/** + * change_bit32 - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + */ +static inline void change_bit32(long nr, uint32_t *addr) +{ + uint32_t mask = BIT32_MASK(nr); + uint32_t *p = addr + BIT32_WORD(nr); + + *p ^= mask; +} + +/** + * test_and_set_bit32 - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + */ +static inline int test_and_set_bit32(long nr, uint32_t *addr) +{ + uint32_t mask = BIT32_MASK(nr); + uint32_t *p = addr + BIT32_WORD(nr); + uint32_t old = *p; + + *p = old | mask; + return (old & mask) != 0; +} + +/** + * test_and_clear_bit32 - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + */ +static inline int test_and_clear_bit32(long nr, uint32_t *addr) +{ + uint32_t mask = BIT32_MASK(nr); + uint32_t *p = addr + BIT32_WORD(nr); + uint32_t old = *p; + + *p = old & ~mask; + return (old & mask) != 0; +} + +/** + * test_and_change_bit32 - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + */ +static inline int test_and_change_bit32(long nr, uint32_t *addr) +{ + uint32_t mask = BIT32_MASK(nr); + uint32_t *p = addr + BIT32_WORD(nr); + uint32_t old = *p; + + *p = old ^ mask; + return (old & mask) != 0; +} + +/** + * test_bit32 - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static inline int test_bit32(long nr, const uint32_t *addr) +{ + return 1U & (addr[BIT32_WORD(nr)] >> (nr & 31)); +} + +/** + * DOC: Miscellaneous bit operations on single values + * + * These functions are a collection of useful operations + * (rotations, bit extract, bit deposit, etc) on single + * integer values. + */ + +/** * rol8 - rotate an 8-bit value left * @word: value to rotate * @shift: bits to roll diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index 622c9a0232..0fba36ae02 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -803,6 +803,7 @@ void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id, qemu_plugin_udata_cb_t cb, void *userdata); /* returns how many vcpus were started at this point */ +QEMU_PLUGIN_API int qemu_plugin_num_vcpus(void); /** diff --git a/linux-user/aarch64/Makefile.vdso b/linux-user/aarch64/Makefile.vdso index 599958116b..c33a679c0f 100644 --- a/linux-user/aarch64/Makefile.vdso +++ b/linux-user/aarch64/Makefile.vdso @@ -5,8 +5,9 @@ VPATH += $(SUBDIR) all: $(SUBDIR)/vdso-be.so $(SUBDIR)/vdso-le.so -LDFLAGS = -nostdlib -shared -Wl,-h,linux-vdso.so.1 -Wl,--build-id=sha1 \ - -Wl,--hash-style=both -Wl,-T,$(SUBDIR)/vdso.ld +LDFLAGS = -nostdlib -shared -Wl,-h,linux-vdso.so.1 \ + -Wl,--build-id=sha1 -Wl,--hash-style=both \ + -Wl,-z,max-page-size=4096 -Wl,-T,$(SUBDIR)/vdso.ld $(SUBDIR)/vdso-be.so: vdso.S vdso.ld $(CC) -o $@ $(LDFLAGS) -mbig-endian $< diff --git a/linux-user/aarch64/vdso-be.so b/linux-user/aarch64/vdso-be.so index 808206ade8..d43c3b19cd 100755 --- a/linux-user/aarch64/vdso-be.so +++ b/linux-user/aarch64/vdso-be.so Binary files differdiff --git a/linux-user/aarch64/vdso-le.so b/linux-user/aarch64/vdso-le.so index 941aaf2993..aaedc9d85e 100755 --- a/linux-user/aarch64/vdso-le.so +++ b/linux-user/aarch64/vdso-le.so Binary files differdiff --git a/linux-user/arm/Makefile.vdso b/linux-user/arm/Makefile.vdso index 2d098a5748..ede489e236 100644 --- a/linux-user/arm/Makefile.vdso +++ b/linux-user/arm/Makefile.vdso @@ -3,15 +3,18 @@ include $(BUILD_DIR)/tests/tcg/arm-linux-user/config-target.mak SUBDIR = $(SRC_PATH)/linux-user/arm VPATH += $(SUBDIR) -all: $(SUBDIR)/vdso-be.so $(SUBDIR)/vdso-le.so +all: $(SUBDIR)/vdso-be8.so $(SUBDIR)/vdso-be32.so $(SUBDIR)/vdso-le.so # Adding -use-blx disables unneeded interworking without actually using blx. -LDFLAGS = -nostdlib -shared -Wl,-use-blx \ +LDFLAGS = -nostdlib -shared -Wl,-use-blx -Wl,-z,max-page-size=4096 \ -Wl,-h,linux-vdso.so.1 -Wl,--build-id=sha1 \ -Wl,--hash-style=both -Wl,-T,$(SUBDIR)/vdso.ld -$(SUBDIR)/vdso-be.so: vdso.S vdso.ld vdso-asmoffset.h - $(CC) -o $@ $(LDFLAGS) -mbig-endian $< +$(SUBDIR)/vdso-be8.so: vdso.S vdso.ld vdso-asmoffset.h + $(CC) -o $@ $(LDFLAGS) -mbig-endian -mbe8 $< + +$(SUBDIR)/vdso-be32.so: vdso.S vdso.ld vdso-asmoffset.h + $(CC) -o $@ $(LDFLAGS) -mbig-endian -mbe32 $< $(SUBDIR)/vdso-le.so: vdso.S vdso.ld vdso-asmoffset.h $(CC) -o $@ $(LDFLAGS) -mlittle-endian $< diff --git a/linux-user/arm/meson.build b/linux-user/arm/meson.build index c4bb9af5b8..348ffb810d 100644 --- a/linux-user/arm/meson.build +++ b/linux-user/arm/meson.build @@ -10,10 +10,17 @@ syscall_nr_generators += { # is always true as far as source_set.apply() is concerned. Always build # both header files and include the right one via #if. -vdso_be_inc = gen_vdso.process('vdso-be.so', - extra_args: ['-s', 'sigreturn_codes']) +vdso_be8_inc = gen_vdso.process('vdso-be8.so', + extra_args: ['-s', 'sigreturn_codes', + '-p', 'vdso_be8']) + +vdso_be32_inc = gen_vdso.process('vdso-be32.so', + extra_args: ['-s', 'sigreturn_codes', + '-p', 'vdso_be32']) vdso_le_inc = gen_vdso.process('vdso-le.so', extra_args: ['-s', 'sigreturn_codes']) -linux_user_ss.add(when: 'TARGET_ARM', if_true: [vdso_be_inc, vdso_le_inc]) +linux_user_ss.add(when: 'TARGET_ARM', if_true: [ + vdso_be8_inc, vdso_be32_inc, vdso_le_inc +]) diff --git a/linux-user/arm/vdso-be32.so b/linux-user/arm/vdso-be32.so new file mode 100755 index 0000000000..b896d3d545 --- /dev/null +++ b/linux-user/arm/vdso-be32.so Binary files differdiff --git a/linux-user/arm/vdso-be.so b/linux-user/arm/vdso-be8.so index 69cafbb956..784b7bdb2a 100755 --- a/linux-user/arm/vdso-be.so +++ b/linux-user/arm/vdso-be8.so Binary files differdiff --git a/linux-user/arm/vdso-le.so b/linux-user/arm/vdso-le.so index ad05a12518..38d3d51047 100755 --- a/linux-user/arm/vdso-le.so +++ b/linux-user/arm/vdso-le.so Binary files differdiff --git a/linux-user/elfload.c b/linux-user/elfload.c index 6cef8db3b5..471a384b22 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -659,6 +659,23 @@ static const char *get_elf_platform(void) #undef END } +#if TARGET_BIG_ENDIAN +#include "elf.h" +#include "vdso-be8.c.inc" +#include "vdso-be32.c.inc" + +static const VdsoImageInfo *vdso_image_info(uint32_t elf_flags) +{ + return (EF_ARM_EABI_VERSION(elf_flags) >= EF_ARM_EABI_VER4 + && (elf_flags & EF_ARM_BE8) + ? &vdso_be8_image_info + : &vdso_be32_image_info); +} +#define vdso_image_info vdso_image_info +#else +# define VDSO_HEADER "vdso-le.c.inc" +#endif + #else /* 64 bit ARM definitions */ @@ -958,14 +975,14 @@ const char *elf_hwcap2_str(uint32_t bit) #undef GET_FEATURE_ID -#endif /* not TARGET_AARCH64 */ - #if TARGET_BIG_ENDIAN # define VDSO_HEADER "vdso-be.c.inc" #else # define VDSO_HEADER "vdso-le.c.inc" #endif +#endif /* not TARGET_AARCH64 */ + #endif /* TARGET_ARM */ #ifdef TARGET_SPARC @@ -2898,7 +2915,7 @@ static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base, static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root, uintptr_t align, uintptr_t brk) { - uintptr_t last = mmap_min_addr; + uintptr_t last = sizeof(uintptr_t) == 4 ? MiB : GiB; uintptr_t base, skip; while (true) { @@ -3179,7 +3196,8 @@ static void load_elf_image(const char *image_name, const ImageSource *src, char **pinterp_name) { g_autofree struct elf_phdr *phdr = NULL; - abi_ulong load_addr, load_bias, loaddr, hiaddr, error; + abi_ulong load_addr, load_bias, loaddr, hiaddr, error, align; + size_t reserve_size, align_size; int i, prot_exec; Error *err = NULL; @@ -3219,7 +3237,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src, * amount of memory to handle that. Locate the interpreter, if any. */ loaddr = -1, hiaddr = 0; - info->alignment = 0; + align = 0; info->exec_stack = EXSTACK_DEFAULT; for (i = 0; i < ehdr->e_phnum; ++i) { struct elf_phdr *eppnt = phdr + i; @@ -3233,7 +3251,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src, hiaddr = a; } ++info->nsegs; - info->alignment |= eppnt->p_align; + align |= eppnt->p_align; } else if (eppnt->p_type == PT_INTERP && pinterp_name) { g_autofree char *interp_name = NULL; @@ -3263,6 +3281,8 @@ static void load_elf_image(const char *image_name, const ImageSource *src, load_addr = loaddr; + align = pow2ceil(align); + if (pinterp_name != NULL) { if (ehdr->e_type == ET_EXEC) { /* @@ -3271,8 +3291,6 @@ static void load_elf_image(const char *image_name, const ImageSource *src, */ probe_guest_base(image_name, loaddr, hiaddr); } else { - abi_ulong align; - /* * The binary is dynamic, but we still need to * select guest_base. In this case we pass a size. @@ -3290,10 +3308,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src, * Since we do not have complete control over the guest * address space, we prefer the kernel to choose some address * rather than force the use of LOAD_ADDR via MAP_FIXED. - * But without MAP_FIXED we cannot guarantee alignment, - * only suggest it. */ - align = pow2ceil(info->alignment); if (align) { load_addr &= -align; } @@ -3317,13 +3332,35 @@ static void load_elf_image(const char *image_name, const ImageSource *src, * In both cases, we will overwrite pages in this range with mappings * from the executable. */ - load_addr = target_mmap(load_addr, (size_t)hiaddr - loaddr + 1, PROT_NONE, + reserve_size = (size_t)hiaddr - loaddr + 1; + align_size = reserve_size; + + if (ehdr->e_type != ET_EXEC && align > qemu_real_host_page_size()) { + align_size += align - 1; + } + + load_addr = target_mmap(load_addr, align_size, PROT_NONE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | (ehdr->e_type == ET_EXEC ? MAP_FIXED_NOREPLACE : 0), -1, 0); if (load_addr == -1) { goto exit_mmap; } + + if (align_size != reserve_size) { + abi_ulong align_addr = ROUND_UP(load_addr, align); + abi_ulong align_end = align_addr + reserve_size; + abi_ulong load_end = load_addr + align_size; + + if (align_addr != load_addr) { + target_munmap(load_addr, align_addr - load_addr); + } + if (align_end != load_end) { + target_munmap(align_end, load_end - align_end); + } + load_addr = align_addr; + } + load_bias = load_addr - loaddr; if (elf_is_fdpic(ehdr)) { @@ -3504,12 +3541,14 @@ static void load_elf_interp(const char *filename, struct image_info *info, load_elf_image(filename, &src, info, &ehdr, NULL); } +#ifndef vdso_image_info #ifdef VDSO_HEADER #include VDSO_HEADER -#define vdso_image_info() &vdso_image_info +#define vdso_image_info(flags) &vdso_image_info #else -#define vdso_image_info() NULL -#endif +#define vdso_image_info(flags) NULL +#endif /* VDSO_HEADER */ +#endif /* vdso_image_info */ static void load_elf_vdso(struct image_info *info, const VdsoImageInfo *vdso) { @@ -3840,7 +3879,7 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) * Load a vdso if available, which will amongst other things contain the * signal trampolines. Otherwise, allocate a separate page for them. */ - const VdsoImageInfo *vdso = vdso_image_info(); + const VdsoImageInfo *vdso = vdso_image_info(info->elf_flags); if (vdso) { load_elf_vdso(&vdso_info, vdso); info->vdso = vdso_info.load_bias; diff --git a/linux-user/loongarch64/Makefile.vdso b/linux-user/loongarch64/Makefile.vdso index 369de13344..1d760b1e47 100644 --- a/linux-user/loongarch64/Makefile.vdso +++ b/linux-user/loongarch64/Makefile.vdso @@ -8,4 +8,5 @@ all: $(SUBDIR)/vdso.so $(SUBDIR)/vdso.so: vdso.S vdso.ld vdso-asmoffset.h $(CC) -o $@ -nostdlib -shared -fpic -Wl,-h,linux-vdso.so.1 \ -Wl,--build-id=sha1 -Wl,--hash-style=both \ - -Wl,--no-warn-rwx-segments -Wl,-T,$(SUBDIR)/vdso.ld $< + -Wl,--no-warn-rwx-segments -Wl,-z,max-page-size=4096 \ + -Wl,-T,$(SUBDIR)/vdso.ld $< diff --git a/linux-user/loongarch64/vdso.so b/linux-user/loongarch64/vdso.so index bfaa26f2bf..7c2de6c50e 100755 --- a/linux-user/loongarch64/vdso.so +++ b/linux-user/loongarch64/vdso.so Binary files differdiff --git a/linux-user/ppc/Makefile.vdso b/linux-user/ppc/Makefile.vdso index 3ca3c6b83e..e2b8facbb5 100644 --- a/linux-user/ppc/Makefile.vdso +++ b/linux-user/ppc/Makefile.vdso @@ -6,9 +6,11 @@ VPATH += $(SUBDIR) all: $(SUBDIR)/vdso-32.so $(SUBDIR)/vdso-64.so $(SUBDIR)/vdso-64le.so LDFLAGS32 = -nostdlib -shared -Wl,-T,$(SUBDIR)/vdso-32.ld \ - -Wl,-h,linux-vdso32.so.1 -Wl,--hash-style=both -Wl,--build-id=sha1 + -Wl,-h,linux-vdso32.so.1 -Wl,--hash-style=both \ + -Wl,--build-id=sha1 -Wl,-z,max-page-size=4096 LDFLAGS64 = -nostdlib -shared -Wl,-T,$(SUBDIR)/vdso-64.ld \ - -Wl,-h,linux-vdso64.so.1 -Wl,--hash-style=both -Wl,--build-id=sha1 + -Wl,-h,linux-vdso64.so.1 -Wl,--hash-style=both \ + -Wl,--build-id=sha1 -Wl,-z,max-page-size=4096 $(SUBDIR)/vdso-32.so: vdso.S vdso-32.ld vdso-asmoffset.h $(CC) -o $@ $(LDFLAGS32) -m32 $< diff --git a/linux-user/ppc/vdso-32.so b/linux-user/ppc/vdso-32.so index b19baafb0d..0dc55e0ddd 100755 --- a/linux-user/ppc/vdso-32.so +++ b/linux-user/ppc/vdso-32.so Binary files differdiff --git a/linux-user/ppc/vdso-64.so b/linux-user/ppc/vdso-64.so index 913c831b38..ac1ab2582e 100755 --- a/linux-user/ppc/vdso-64.so +++ b/linux-user/ppc/vdso-64.so Binary files differdiff --git a/linux-user/ppc/vdso-64le.so b/linux-user/ppc/vdso-64le.so index 258a03b807..424abb4290 100755 --- a/linux-user/ppc/vdso-64le.so +++ b/linux-user/ppc/vdso-64le.so Binary files differdiff --git a/linux-user/qemu.h b/linux-user/qemu.h index 895bdd722a..67bc81b149 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -44,7 +44,6 @@ struct image_info { abi_ulong file_string; uint32_t elf_flags; int personality; - abi_ulong alignment; bool exec_stack; /* Generic semihosting knows about these pointers. */ diff --git a/linux-user/strace.c b/linux-user/strace.c index b70eadc19e..3b744ccd4a 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -3971,7 +3971,7 @@ print_mmap(CPUArchState *cpu_env, const struct syscallname *name, { return print_mmap_both(cpu_env, name, arg0, arg1, arg2, arg3, arg4, arg5, -#if defined(TARGET_NR_mmap2) +#ifdef TARGET_ARCH_WANT_SYS_OLD_MMAP true #else false @@ -4401,7 +4401,7 @@ print_syscall(CPUArchState *cpu_env, int num, if (!f) { return; } - fprintf(f, "%d ", getpid()); + fprintf(f, "%d ", get_task_state(env_cpu(cpu_env))->ts_tid); for (i = 0; i < nsyscalls; i++) { if (scnames[i].nr == num) { diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 59b2080b98..1ce4c79784 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7233,12 +7233,24 @@ static inline int tswapid(int id) #else #define __NR_sys_setgroups __NR_setgroups #endif +#ifdef __NR_sys_setreuid32 +#define __NR_sys_setreuid __NR_setreuid32 +#else +#define __NR_sys_setreuid __NR_setreuid +#endif +#ifdef __NR_sys_setregid32 +#define __NR_sys_setregid __NR_setregid32 +#else +#define __NR_sys_setregid __NR_setregid +#endif _syscall1(int, sys_setuid, uid_t, uid) _syscall1(int, sys_setgid, gid_t, gid) _syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) _syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) _syscall2(int, sys_setgroups, int, size, gid_t *, grouplist) +_syscall2(int, sys_setreuid, uid_t, ruid, uid_t, euid); +_syscall2(int, sys_setregid, gid_t, rgid, gid_t, egid); void syscall_init(void) { @@ -10576,10 +10588,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, return ret; #ifdef TARGET_NR_mmap case TARGET_NR_mmap: -#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \ - (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \ - defined(TARGET_M68K) || defined(TARGET_MICROBLAZE) \ - || defined(TARGET_S390X) +#ifdef TARGET_ARCH_WANT_SYS_OLD_MMAP { abi_ulong *v; abi_ulong v1, v2, v3, v4, v5, v6; @@ -11932,9 +11941,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, return get_errno(high2lowgid(getegid())); #endif case TARGET_NR_setreuid: - return get_errno(setreuid(low2highuid(arg1), low2highuid(arg2))); + return get_errno(sys_setreuid(low2highuid(arg1), low2highuid(arg2))); case TARGET_NR_setregid: - return get_errno(setregid(low2highgid(arg1), low2highgid(arg2))); + return get_errno(sys_setregid(low2highgid(arg1), low2highgid(arg2))); case TARGET_NR_getgroups: { /* the same code as for TARGET_NR_getgroups32 */ int gidsetsize = arg1; @@ -12264,11 +12273,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_setreuid32 case TARGET_NR_setreuid32: - return get_errno(setreuid(arg1, arg2)); + return get_errno(sys_setreuid(arg1, arg2)); #endif #ifdef TARGET_NR_setregid32 case TARGET_NR_setregid32: - return get_errno(setregid(arg1, arg2)); + return get_errno(sys_setregid(arg1, arg2)); #endif #ifdef TARGET_NR_getgroups32 case TARGET_NR_getgroups32: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 0e08dfae3e..faad9147c9 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2766,4 +2766,11 @@ struct target_open_how_ver0 { #define RESOLVE_NO_SYMLINKS 0x04 #endif +#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \ + (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \ + defined(TARGET_M68K) || defined(TARGET_MICROBLAZE) || \ + defined(TARGET_S390X) +#define TARGET_ARCH_WANT_SYS_OLD_MMAP +#endif + #endif diff --git a/meson.build b/meson.build index e0b880e4e1..a290dbfa33 100644 --- a/meson.build +++ b/meson.build @@ -315,8 +315,8 @@ foreach lang : all_languages # ok elif compiler.get_id() == 'clang' and compiler.compiles(''' #ifdef __apple_build_version__ - # if __clang_major__ < 12 || (__clang_major__ == 12 && __clang_minor__ < 0) - # error You need at least XCode Clang v12.0 to compile QEMU + # if __clang_major__ < 15 || (__clang_major__ == 15 && __clang_minor__ < 0) + # error You need at least XCode Clang v15.0 to compile QEMU # endif #else # if __clang_major__ < 10 || (__clang_major__ == 10 && __clang_minor__ < 0) @@ -325,7 +325,7 @@ foreach lang : all_languages #endif''') # ok else - error('You either need GCC v7.4 or Clang v10.0 (or XCode Clang v12.0) to compile QEMU') + error('You either need GCC v7.4 or Clang v10.0 (or XCode Clang v15.0) to compile QEMU') endif endforeach diff --git a/migration/fd.c b/migration/fd.c index aab5189eac..9bf9be6acb 100644 --- a/migration/fd.c +++ b/migration/fd.c @@ -25,6 +25,29 @@ #include "io/channel-util.h" #include "trace.h" +static bool fd_is_pipe(int fd) +{ + struct stat statbuf; + + if (fstat(fd, &statbuf) == -1) { + return false; + } + + return S_ISFIFO(statbuf.st_mode); +} + +static bool migration_fd_valid(int fd) +{ + if (fd_is_socket(fd)) { + return true; + } + + if (fd_is_pipe(fd)) { + return true; + } + + return false; +} void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp) { @@ -34,7 +57,7 @@ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error ** return; } - if (!fd_is_socket(fd)) { + if (!migration_fd_valid(fd)) { warn_report("fd: migration to a file is deprecated." " Use file: instead."); } @@ -68,7 +91,7 @@ void fd_start_incoming_migration(const char *fdname, Error **errp) return; } - if (!fd_is_socket(fd)) { + if (!migration_fd_valid(fd)) { warn_report("fd: migration to a file is deprecated." " Use file: instead."); } diff --git a/migration/migration.c b/migration/migration.c index aedf7f0751..8c5bd0a75c 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1117,6 +1117,10 @@ bool migration_is_running(void) { MigrationState *s = current_migration; + if (!s) { + return false; + } + switch (s->state) { case MIGRATION_STATUS_ACTIVE: case MIGRATION_STATUS_POSTCOPY_ACTIVE: diff --git a/migration/migration.h b/migration/migration.h index 0956e9274b..3857905c0e 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -37,7 +37,7 @@ #define MIGRATION_THREAD_SRC_TLS "mig/src/tls" #define MIGRATION_THREAD_DST_COLO "mig/dst/colo" -#define MIGRATION_THREAD_DST_MULTIFD "mig/src/recv_%d" +#define MIGRATION_THREAD_DST_MULTIFD "mig/dst/recv_%d" #define MIGRATION_THREAD_DST_FAULT "mig/dst/fault" #define MIGRATION_THREAD_DST_LISTEN "mig/dst/listen" #define MIGRATION_THREAD_DST_PREEMPT "mig/dst/preempt" diff --git a/migration/multifd.c b/migration/multifd.c index 4374e14a96..498e71fd10 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -623,7 +623,7 @@ static void *multifd_send_thread(void *opaque) } stat64_add(&mig_stats.multifd_bytes, - p->next_packet_size + p->packet_len); + (uint64_t)p->next_packet_size + p->packet_len); p->next_packet_size = 0; multifd_set_payload_type(p->data, MULTIFD_PAYLOAD_NONE); diff --git a/migration/savevm.c b/migration/savevm.c index f4e4876f72..98821c8120 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -2057,7 +2057,6 @@ static void *postcopy_ram_listen_thread(void *opaque) * got a bad migration state). */ migration_incoming_state_destroy(); - qemu_loadvm_state_cleanup(); rcu_unregister_thread(); mis->have_listen_thread = false; diff --git a/nbd/server.c b/nbd/server.c index c30e687fc8..f64e47270c 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1150,8 +1150,8 @@ nbd_negotiate_meta_queries(NBDClient *client, Error **errp) * Return: * -errno on error, errp is set * 0 on successful negotiation, errp is not set - * 1 if client sent NBD_OPT_ABORT, i.e. on valid disconnect, - * errp is not set + * 1 if client sent NBD_OPT_ABORT (i.e. on valid disconnect) or never + * wrote anything (i.e. port probe); errp is not set */ static coroutine_fn int nbd_negotiate_options(NBDClient *client, Error **errp) @@ -1175,8 +1175,13 @@ nbd_negotiate_options(NBDClient *client, Error **errp) ... Rest of request */ - if (nbd_read32(client->ioc, &flags, "flags", errp) < 0) { - return -EIO; + /* + * Intentionally ignore errors on this first read - we do not want + * to be noisy about a mere port probe, but only for clients that + * start talking the protocol and then quit abruptly. + */ + if (nbd_read32(client->ioc, &flags, "flags", NULL) < 0) { + return 1; } client->mode = NBD_MODE_EXPORT_NAME; trace_nbd_negotiate_options_flags(flags); @@ -1383,8 +1388,8 @@ nbd_negotiate_options(NBDClient *client, Error **errp) * Return: * -errno on error, errp is set * 0 on successful negotiation, errp is not set - * 1 if client sent NBD_OPT_ABORT, i.e. on valid disconnect, - * errp is not set + * 1 if client sent NBD_OPT_ABORT (i.e. on valid disconnect) or never + * wrote anything (i.e. port probe); errp is not set */ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) { @@ -1415,9 +1420,12 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) stq_be_p(buf + 8, NBD_OPTS_MAGIC); stw_be_p(buf + 16, NBD_FLAG_FIXED_NEWSTYLE | NBD_FLAG_NO_ZEROES); - if (nbd_write(client->ioc, buf, 18, errp) < 0) { - error_prepend(errp, "write failed: "); - return -EINVAL; + /* + * Be silent about failure to write our greeting: there is nothing + * wrong with a client testing if our port is alive. + */ + if (nbd_write(client->ioc, buf, 18, NULL) < 0) { + return 1; } ret = nbd_negotiate_options(client, errp); if (ret != 0) { diff --git a/net/checksum.c b/net/checksum.c index 1a957e4c0b..537457d89d 100644 --- a/net/checksum.c +++ b/net/checksum.c @@ -57,7 +57,7 @@ uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, return net_checksum_finish(sum); } -void net_checksum_calculate(uint8_t *data, int length, int csum_flag) +void net_checksum_calculate(void *data, int length, int csum_flag) { int mac_hdr_len, ip_len; struct ip_header *ip; @@ -101,7 +101,7 @@ void net_checksum_calculate(uint8_t *data, int length, int csum_flag) return; } - ip = (struct ip_header *)(data + mac_hdr_len); + ip = (struct ip_header *)((uint8_t *)data + mac_hdr_len); if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { return; /* not IPv4 */ diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index f9bac25306..0cbedf0fa6 100644 --- a/pc-bios/s390-ccw.img +++ b/pc-bios/s390-ccw.img Binary files differdiff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index a4d1c05aac..76bf743900 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -191,7 +191,7 @@ static void boot_setup(void) { char lpmsg[] = "LOADPARM=[________]\n"; - if (memcmp(iplb.loadparm, NO_LOADPARM, LOADPARM_LEN) != 0) { + if (have_iplb && memcmp(iplb.loadparm, NO_LOADPARM, LOADPARM_LEN) != 0) { ebcdic_to_ascii((char *) iplb.loadparm, loadparm_str, LOADPARM_LEN); } else { sclp_get_loadparm_ascii(loadparm_str); @@ -242,6 +242,7 @@ static bool find_boot_device(void) static int virtio_setup(void) { VDev *vdev = virtio_get_device(); + vdev->is_cdrom = false; int ret; switch (vdev->senseid.cu_model) { @@ -315,6 +316,7 @@ void main(void) css_setup(); have_iplb = store_iplb(&iplb); if (!have_iplb) { + boot_setup(); probe_boot_device(); } diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c index f9854a22c3..578c89d0c5 100644 --- a/pc-bios/s390-ccw/virtio-net.c +++ b/pc-bios/s390-ccw/virtio-net.c @@ -51,6 +51,8 @@ int virtio_net_init(void *mac_addr) void *buf; int i; + rx_last_idx = 0; + vdev->guest_features[0] = VIRTIO_NET_F_MAC_BIT; virtio_setup_ccw(vdev); diff --git a/plugins/meson.build b/plugins/meson.build index 1cc039d29b..98542e926f 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -2,17 +2,23 @@ if not get_option('plugins') subdir_done() endif +qemu_plugin_symbols = configure_file( + input: files('../include/qemu/qemu-plugin.h'), + output: 'qemu-plugin.symbols', + capture: true, + command: [files('../scripts/qemu-plugin-symbols.py'), '@INPUT@']) + # Modules need more symbols than just those in plugins/qemu-plugins.symbols if not enable_modules if host_os == 'darwin' configure_file( - input: files('qemu-plugins.symbols'), + input: qemu_plugin_symbols, output: 'qemu-plugins-ld64.symbols', capture: true, command: ['sed', '-ne', 's/^[[:space:]]*\\(qemu_.*\\);/_\\1/p', '@INPUT@']) emulator_link_args += ['-Wl,-exported_symbols_list,plugins/qemu-plugins-ld64.symbols'] else - emulator_link_args += ['-Xlinker', '--dynamic-list=' + (meson.project_source_root() / 'plugins/qemu-plugins.symbols')] + emulator_link_args += ['-Xlinker', '--dynamic-list=' + qemu_plugin_symbols.full_path()] endif endif @@ -23,7 +29,7 @@ if host_os == 'windows' # First, create a .def file listing all the symbols a plugin should expect to have # available in qemu win32_plugin_def = configure_file( - input: files('qemu-plugins.symbols'), + input: qemu_plugin_symbols, output: 'qemu_plugin_api.def', capture: true, command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@']) diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols deleted file mode 100644 index 032661f9ea..0000000000 --- a/plugins/qemu-plugins.symbols +++ /dev/null @@ -1,59 +0,0 @@ -{ - qemu_plugin_bool_parse; - qemu_plugin_end_code; - qemu_plugin_entry_code; - qemu_plugin_get_hwaddr; - qemu_plugin_get_registers; - qemu_plugin_hwaddr_device_name; - qemu_plugin_hwaddr_is_io; - qemu_plugin_hwaddr_phys_addr; - qemu_plugin_insn_data; - qemu_plugin_insn_disas; - qemu_plugin_insn_haddr; - qemu_plugin_insn_size; - qemu_plugin_insn_symbol; - qemu_plugin_insn_vaddr; - qemu_plugin_mem_get_value; - qemu_plugin_mem_is_big_endian; - qemu_plugin_mem_is_sign_extended; - qemu_plugin_mem_is_store; - qemu_plugin_mem_size_shift; - qemu_plugin_num_vcpus; - qemu_plugin_outs; - qemu_plugin_path_to_binary; - qemu_plugin_read_memory_vaddr; - qemu_plugin_read_register; - qemu_plugin_register_atexit_cb; - qemu_plugin_register_flush_cb; - qemu_plugin_register_vcpu_exit_cb; - qemu_plugin_register_vcpu_idle_cb; - qemu_plugin_register_vcpu_init_cb; - qemu_plugin_register_vcpu_insn_exec_cb; - qemu_plugin_register_vcpu_insn_exec_cond_cb; - qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu; - qemu_plugin_register_vcpu_mem_cb; - qemu_plugin_register_vcpu_mem_inline_per_vcpu; - qemu_plugin_register_vcpu_resume_cb; - qemu_plugin_register_vcpu_syscall_cb; - qemu_plugin_register_vcpu_syscall_ret_cb; - qemu_plugin_register_vcpu_tb_exec_cb; - qemu_plugin_register_vcpu_tb_exec_cond_cb; - qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu; - qemu_plugin_register_vcpu_tb_trans_cb; - qemu_plugin_request_time_control; - qemu_plugin_reset; - qemu_plugin_scoreboard_free; - qemu_plugin_scoreboard_find; - qemu_plugin_scoreboard_new; - qemu_plugin_start_code; - qemu_plugin_tb_get_insn; - qemu_plugin_tb_n_insns; - qemu_plugin_tb_vaddr; - qemu_plugin_u64_add; - qemu_plugin_u64_get; - qemu_plugin_u64_set; - qemu_plugin_u64_sum; - qemu_plugin_uninstall; - qemu_plugin_update_ns; - qemu_plugin_vcpu_for_each; -}; diff --git a/python/scripts/mkvenv.py b/python/scripts/mkvenv.py index f2526af0a0..8ac5b0b2a0 100644 --- a/python/scripts/mkvenv.py +++ b/python/scripts/mkvenv.py @@ -379,6 +379,9 @@ def make_venv( # pylint: disable=too-many-arguments try: builder.create(str(env_dir)) except SystemExit as exc: + # pylint 3.3 bug: + # pylint: disable=raising-non-exception, raise-missing-from + # Some versions of the venv module raise SystemExit; *nasty*! # We want the exception that prompted it. It might be a subprocess # error that has output we *really* want to see. diff --git a/python/setup.cfg b/python/setup.cfg index 3b4e2cc550..cf5af7e664 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -142,6 +142,7 @@ ignore_missing_imports = True disable=consider-using-f-string, consider-using-with, too-many-arguments, + too-many-positional-arguments, too-many-function-args, # mypy handles this with less false positives. too-many-instance-attributes, no-member, # mypy also handles this better. diff --git a/qapi/qdev.json b/qapi/qdev.json index 2a581129c9..25cbcf977b 100644 --- a/qapi/qdev.json +++ b/qapi/qdev.json @@ -182,7 +182,7 @@ # # @unstable: The command is experimental. # -# Since: 9.1 +# Since: 9.2 ## { 'command': 'device-sync-config', 'features': [ 'unstable' ], diff --git a/qapi/qom.json b/qapi/qom.json index a8beeabf1f..28ce24cd8d 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -877,7 +877,7 @@ # complex as there may be interleaving across multiple devices # and shared links in the path. # -# Since: 9.1 +# Since: 9.2 ## { 'struct': 'AcpiGenericPortProperties', 'data': { 'pci-bus': 'str', diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 2a85960b81..476cacc844 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -182,7 +182,7 @@ impl PL011State { use RegisterOffset::*; std::ops::ControlFlow::Break(match RegisterOffset::try_from(offset) { - Err(v) if (0x3f8..0x400).contains(&v) => { + Err(v) if (0x3f8..0x400).contains(&(v >> 2)) => { u64::from(self.device_id[(offset - 0xfe0) >> 2]) } Err(_) => { diff --git a/scripts/qemu-plugin-symbols.py b/scripts/qemu-plugin-symbols.py new file mode 100755 index 0000000000..e285ebb8f9 --- /dev/null +++ b/scripts/qemu-plugin-symbols.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Extract QEMU Plugin API symbols from a header file +# +# Copyright 2024 Linaro Ltd +# +# Author: Pierrick Bouvier <pierrick.bouvier@linaro.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. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import argparse +import re + +def extract_symbols(plugin_header): + with open(plugin_header) as file: + content = file.read() + # Remove QEMU_PLUGIN_API macro definition. + content = content.replace('#define QEMU_PLUGIN_API', '') + expected = content.count('QEMU_PLUGIN_API') + # Find last word between QEMU_PLUGIN_API and (, matching on several lines. + # We use *? non-greedy quantifier. + syms = re.findall(r'QEMU_PLUGIN_API.*?(\w+)\s*\(', content, re.DOTALL) + syms.sort() + # Ensure we found as many symbols as API markers. + assert len(syms) == expected + return syms + +def main() -> None: + parser = argparse.ArgumentParser(description='Extract QEMU plugin symbols') + parser.add_argument('plugin_header', help='Path to QEMU plugin header.') + args = parser.parse_args() + + syms = extract_symbols(args.plugin_header) + + print('{') + for s in syms: + print(" {};".format(s)) + print('};') + +if __name__ == '__main__': + main() diff --git a/system/dma-helpers.c b/system/dma-helpers.c index 74013308f5..cbcd89dfaa 100644 --- a/system/dma-helpers.c +++ b/system/dma-helpers.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "sysemu/block-backend.h" #include "sysemu/dma.h" -#include "trace/trace-root.h" +#include "trace.h" #include "qemu/thread.h" #include "qemu/main-loop.h" #include "sysemu/cpu-timers.h" diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index 4c09b38ffb..03ae610649 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -856,18 +856,9 @@ void hmp_info_qdm(Monitor *mon, const QDict *qdict) void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp) { - QemuOpts *opts; DeviceState *dev; - opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, errp); - if (!opts) { - return; - } - if (!monitor_cur_is_qmp() && qdev_device_help(opts)) { - qemu_opts_del(opts); - return; - } - dev = qdev_device_add(opts, errp); + dev = qdev_device_add_from_qdict(qdict, true, errp); if (!dev) { /* * Drain all pending RCU callbacks. This is done because @@ -879,9 +870,6 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp) * to the user */ drain_call_rcu(); - - qemu_opts_del(opts); - return; } object_unref(OBJECT(dev)); } @@ -1018,8 +1006,34 @@ void qmp_device_sync_config(const char *id, Error **errp) void hmp_device_add(Monitor *mon, const QDict *qdict) { Error *err = NULL; + QemuOpts *opts; + DeviceState *dev; - qmp_device_add((QDict *)qdict, NULL, &err); + opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &err); + if (!opts) { + goto out; + } + if (qdev_device_help(opts)) { + qemu_opts_del(opts); + return; + } + dev = qdev_device_add(opts, &err); + if (!dev) { + /* + * Drain all pending RCU callbacks. This is done because + * some bus related operations can delay a device removal + * (in this case this can happen if device is added and then + * removed due to a configuration error) + * to a RCU callback, but user might expect that this interface + * will finish its job completely once qmp command returns result + * to the user + */ + drain_call_rcu(); + + qemu_opts_del(opts); + } + object_unref(dev); +out: hmp_handle_error(mon, err); } diff --git a/system/trace-events b/system/trace-events index 2ed1d59b1f..5bbc3fbffa 100644 --- a/system/trace-events +++ b/system/trace-events @@ -4,6 +4,13 @@ # Since requests are raised via monitor, not many tracepoints are needed. balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu" +# dma-helpers.c +dma_blk_io(void *dbs, void *bs, int64_t offset, bool to_dev) "dbs=%p bs=%p offset=%" PRId64 " to_dev=%d" +dma_aio_cancel(void *dbs) "dbs=%p" +dma_complete(void *dbs, int ret, void *cb) "dbs=%p ret=%d cb=%p" +dma_blk_cb(void *dbs, int ret) "dbs=%p ret=%d" +dma_map_wait(void *dbs) "dbs=%p" + # ioport.c cpu_in(unsigned int addr, char size, unsigned int val) "addr 0x%x(%c) value %u" cpu_out(unsigned int addr, char size, unsigned int val) "addr 0x%x(%c) value %u" diff --git a/system/vl.c b/system/vl.c index d217b3d64d..54998fdbc7 100644 --- a/system/vl.c +++ b/system/vl.c @@ -2427,15 +2427,15 @@ static void qemu_validate_options(const QDict *machine_opts) const char *kernel_cmdline = qdict_get_try_str(machine_opts, "append"); if (kernel_filename == NULL) { - if (kernel_cmdline != NULL) { - error_report("-append only allowed with -kernel option"); - exit(1); - } + if (kernel_cmdline != NULL) { + error_report("-append only allowed with -kernel option"); + exit(1); + } - if (initrd_filename != NULL) { - error_report("-initrd only allowed with -kernel option"); - exit(1); - } + if (initrd_filename != NULL) { + error_report("-initrd only allowed with -kernel option"); + exit(1); + } } if (loadvm && incoming) { @@ -2653,17 +2653,11 @@ static void qemu_create_cli_devices(void) qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, &error_fatal); QTAILQ_FOREACH(opt, &device_opts, next) { - DeviceState *dev; + QObject *ret_data = NULL; + loc_push_restore(&opt->loc); - /* - * TODO Eventually we should call qmp_device_add() here to make sure it - * behaves the same, but QMP still has to accept incorrectly typed - * options until libvirt is fixed and we want to be strict on the CLI - * from the start, so call qdev_device_add_from_qdict() directly for - * now. - */ - dev = qdev_device_add_from_qdict(opt->opts, true, &error_fatal); - object_unref(OBJECT(dev)); + qmp_device_add(opt->opts, &ret_data, &error_fatal); + assert(ret_data == NULL); /* error_fatal aborts */ loc_pop(&opt->loc); } rom_reset_order_override(); diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 6cea483d42..ca7ea92774 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -31,7 +31,7 @@ #include "target/arm/internals.h" #include "target/arm/multiprocessing.h" #include "target/arm/gtimer.h" -#include "trace/trace-target_arm_hvf.h" +#include "trace.h" #include "migration/vmstate.h" #include "gdbstub/enums.h" diff --git a/target/arm/hvf/trace.h b/target/arm/hvf/trace.h new file mode 100644 index 0000000000..04a19c1d75 --- /dev/null +++ b/target/arm/hvf/trace.h @@ -0,0 +1 @@ +#include "trace/trace-target_arm_hvf.h" diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 9849949508..64bb6878a4 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -85,6 +85,10 @@ static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw, GetPhysAddrResult *result, ARMMMUFaultInfo *fi); +static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, + int user_rw, int prot_rw, int xn, int pxn, + ARMSecuritySpace in_pa, ARMSecuritySpace out_pa); + /* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ static const uint8_t pamax_map[] = { [0] = 32, @@ -1148,7 +1152,7 @@ static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw, hwaddr phys_addr; uint32_t dacr; bool ns; - int user_prot; + ARMSecuritySpace out_space; /* Pagetable walk. */ /* Lookup l1 descriptor. */ @@ -1240,16 +1244,19 @@ static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw, g_assert_not_reached(); } } + out_space = ptw->in_space; + if (ns) { + /* + * The NS bit will (as required by the architecture) have no effect if + * the CPU doesn't support TZ or this is a non-secure translation + * regime, because the output space will already be non-secure. + */ + out_space = ARMSS_NonSecure; + } if (domain_prot == 3) { result->f.prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; } else { - if (pxn && !regime_is_user(env, mmu_idx)) { - xn = 1; - } - if (xn && access_type == MMU_INST_FETCH) { - fi->type = ARMFault_Permission; - goto do_fault; - } + int user_rw, prot_rw; if (arm_feature(env, ARM_FEATURE_V6K) && (regime_sctlr(env, mmu_idx) & SCTLR_AFE)) { @@ -1259,37 +1266,23 @@ static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw, fi->type = ARMFault_AccessFlag; goto do_fault; } - result->f.prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1); - user_prot = simple_ap_to_rw_prot_is_user(ap >> 1, 1); + prot_rw = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1); + user_rw = simple_ap_to_rw_prot_is_user(ap >> 1, 1); } else { - result->f.prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); - user_prot = ap_to_rw_prot_is_user(env, mmu_idx, ap, domain_prot, 1); - } - if (result->f.prot && !xn) { - result->f.prot |= PAGE_EXEC; + prot_rw = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); + user_rw = ap_to_rw_prot_is_user(env, mmu_idx, ap, domain_prot, 1); } + + result->f.prot = get_S1prot(env, mmu_idx, false, user_rw, prot_rw, + xn, pxn, result->f.attrs.space, out_space); if (!(result->f.prot & (1 << access_type))) { /* Access permission fault. */ fi->type = ARMFault_Permission; goto do_fault; } - if (regime_is_pan(env, mmu_idx) && - !regime_is_user(env, mmu_idx) && - user_prot && - access_type != MMU_INST_FETCH) { - /* Privileged Access Never fault */ - fi->type = ARMFault_Permission; - goto do_fault; - } - } - if (ns) { - /* The NS bit will (as required by the architecture) have no effect if - * the CPU doesn't support TZ or this is a non-secure translation - * regime, because the attribute will already be non-secure. - */ - result->f.attrs.secure = false; - result->f.attrs.space = ARMSS_NonSecure; } + result->f.attrs.space = out_space; + result->f.attrs.secure = arm_space_is_secure(out_space); result->f.phys_addr = phys_addr; return false; do_fault: @@ -1357,25 +1350,24 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) * @env: CPUARMState * @mmu_idx: MMU index indicating required translation regime * @is_aa64: TRUE if AArch64 - * @ap: The 2-bit simple AP (AP[2:1]) + * @user_rw: Translated AP for user access + * @prot_rw: Translated AP for privileged access * @xn: XN (execute-never) bit * @pxn: PXN (privileged execute-never) bit * @in_pa: The original input pa space * @out_pa: The output pa space, modified by NSTable, NS, and NSE */ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, - int ap, int xn, int pxn, + int user_rw, int prot_rw, int xn, int pxn, ARMSecuritySpace in_pa, ARMSecuritySpace out_pa) { ARMCPU *cpu = env_archcpu(env); bool is_user = regime_is_user(env, mmu_idx); - int prot_rw, user_rw; bool have_wxn; int wxn = 0; assert(!regime_is_stage2(mmu_idx)); - user_rw = simple_ap_to_rw_prot_is_user(ap, true); if (is_user) { prot_rw = user_rw; } else { @@ -1393,8 +1385,6 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, regime_is_pan(env, mmu_idx) && (regime_sctlr(env, mmu_idx) & SCTLR_EPAN) && !xn) { prot_rw = 0; - } else { - prot_rw = simple_ap_to_rw_prot_is_user(ap, false); } } @@ -2044,6 +2034,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, int nse, ns = extract32(attrs, 5, 1); uint8_t attrindx; uint64_t mair; + int user_rw, prot_rw; switch (out_space) { case ARMSS_Root: @@ -2110,12 +2101,15 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, xn = 0; ap &= ~1; } + + user_rw = simple_ap_to_rw_prot_is_user(ap, true); + prot_rw = simple_ap_to_rw_prot_is_user(ap, false); /* * Note that we modified ptw->in_space earlier for NSTable, but * result->f.attrs retains a copy of the original security space. */ - result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, xn, pxn, - result->f.attrs.space, out_space); + result->f.prot = get_S1prot(env, mmu_idx, aarch64, user_rw, prot_rw, + xn, pxn, result->f.attrs.space, out_space); /* Index into MAIR registers for cache attributes */ attrindx = extract32(attrs, 2, 3); diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c index 20c2737f17..2ad2182525 100644 --- a/target/arm/tcg/cpu32.c +++ b/target/arm/tcg/cpu32.c @@ -71,7 +71,7 @@ void aa32_max_features(ARMCPU *cpu) cpu->isar.id_mmfr5 = t; t = cpu->isar.id_pfr0; - t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CVS2 */ + t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CSV2 */ t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */ t = FIELD_DP32(t, ID_PFR0, RAS, 1); /* FEAT_RAS */ cpu->isar.id_pfr0 = t; @@ -574,9 +574,9 @@ static void cortex_a15_initfn(Object *obj) static const ARMCPRegInfo cortexr5_cp_reginfo[] = { /* Dummy the TCM region regs for the moment */ - { .name = "ATCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0, + { .name = "BTCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST }, - { .name = "BTCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 1, + { .name = "ATCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 1, .access = PL1_RW, .type = ARM_CP_CONST }, { .name = "DCACHE_INVAL", .cp = 15, .opc1 = 0, .crn = 15, .crm = 5, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP }, diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index f1ee0e060f..904296705c 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -6317,9 +6317,6 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, flags = info.page[0].flags | info.page[1].flags; if (unlikely(flags != 0)) { -#ifdef CONFIG_USER_ONLY - g_assert_not_reached(); -#else /* * At least one page includes MMIO. * Any bus operation can fail with cpu_transaction_failed, @@ -6350,7 +6347,6 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, } while (reg_off & 63); } while (reg_off <= reg_last); return; -#endif } mem_off = info.mem_off_first[0]; diff --git a/target/i386/hvf/x86_mmu.c b/target/i386/hvf/x86_mmu.c index 649074a7d2..579d0c3a4c 100644 --- a/target/i386/hvf/x86_mmu.c +++ b/target/i386/hvf/x86_mmu.c @@ -38,6 +38,7 @@ #define LEGACY_PTE_PAGE_MASK (0xffffffffllu << 12) #define PAE_PTE_PAGE_MASK ((-1llu << 12) & ((1llu << 52) - 1)) #define PAE_PTE_LARGE_PAGE_MASK ((-1llu << (21)) & ((1llu << 52) - 1)) +#define PAE_PTE_SUPER_PAGE_MASK ((-1llu << (30)) & ((1llu << 52) - 1)) struct gpt_translation { target_ulong gva; @@ -96,7 +97,7 @@ static bool get_pt_entry(CPUState *cpu, struct gpt_translation *pt, /* test page table entry */ static bool test_pt_entry(CPUState *cpu, struct gpt_translation *pt, - int level, bool *is_large, bool pae) + int level, int *largeness, bool pae) { uint64_t pte = pt->pte[level]; @@ -118,9 +119,9 @@ static bool test_pt_entry(CPUState *cpu, struct gpt_translation *pt, goto exit; } - if (1 == level && pte_large_page(pte)) { + if (level && pte_large_page(pte)) { pt->err_code |= MMU_PAGE_PT; - *is_large = true; + *largeness = level; } if (!level) { pt->err_code |= MMU_PAGE_PT; @@ -152,9 +153,18 @@ static inline uint64_t pse_pte_to_page(uint64_t pte) return ((pte & 0x1fe000) << 19) | (pte & 0xffc00000); } -static inline uint64_t large_page_gpa(struct gpt_translation *pt, bool pae) +static inline uint64_t large_page_gpa(struct gpt_translation *pt, bool pae, + int largeness) { - VM_PANIC_ON(!pte_large_page(pt->pte[1])) + VM_PANIC_ON(!pte_large_page(pt->pte[largeness])) + + /* 1Gib large page */ + if (pae && largeness == 2) { + return (pt->pte[2] & PAE_PTE_SUPER_PAGE_MASK) | (pt->gva & 0x3fffffff); + } + + VM_PANIC_ON(largeness != 1) + /* 2Mb large page */ if (pae) { return (pt->pte[1] & PAE_PTE_LARGE_PAGE_MASK) | (pt->gva & 0x1fffff); @@ -170,7 +180,7 @@ static bool walk_gpt(CPUState *cpu, target_ulong addr, int err_code, struct gpt_translation *pt, bool pae) { int top_level, level; - bool is_large = false; + int largeness = 0; target_ulong cr3 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR3); uint64_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK; @@ -186,19 +196,19 @@ static bool walk_gpt(CPUState *cpu, target_ulong addr, int err_code, for (level = top_level; level > 0; level--) { get_pt_entry(cpu, pt, level, pae); - if (!test_pt_entry(cpu, pt, level - 1, &is_large, pae)) { + if (!test_pt_entry(cpu, pt, level - 1, &largeness, pae)) { return false; } - if (is_large) { + if (largeness) { break; } } - if (!is_large) { + if (!largeness) { pt->gpa = (pt->pte[0] & page_mask) | (pt->gva & 0xfff); } else { - pt->gpa = large_page_gpa(pt, pae); + pt->gpa = large_page_gpa(pt, pae, largeness); } return true; diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c index f09bfbdda5..cdea2ea69d 100644 --- a/target/i386/hvf/x86_task.c +++ b/target/i386/hvf/x86_task.c @@ -122,7 +122,6 @@ void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int rea load_regs(cpu); struct x86_segment_descriptor curr_tss_desc, next_tss_desc; - int ret; x68_segment_selector old_tss_sel = vmx_read_segment_selector(cpu, R_TR); uint64_t old_tss_base = vmx_read_segment_base(cpu, R_TR); uint32_t desc_limit; @@ -138,7 +137,7 @@ void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int rea if (reason == TSR_IDT_GATE && gate_valid) { int dpl; - ret = x86_read_call_gate(cpu, &task_gate_desc, gate); + x86_read_call_gate(cpu, &task_gate_desc, gate); dpl = task_gate_desc.dpl; x68_segment_selector cs = vmx_read_segment_selector(cpu, R_CS); @@ -167,11 +166,12 @@ void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int rea x86_write_segment_descriptor(cpu, &next_tss_desc, tss_sel); } - if (next_tss_desc.type & 8) - ret = task_switch_32(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); - else + if (next_tss_desc.type & 8) { + task_switch_32(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); + } else { //ret = task_switch_16(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); VM_PANIC("task_switch_16"); + } macvm_set_cr0(cpu->accel->fd, rvmcs(cpu->accel->fd, VMCS_GUEST_CR0) | CR0_TS_MASK); diff --git a/target/i386/kvm/hyperv-stub.c b/target/i386/kvm/hyperv-stub.c index 3263dcf05d..5836f53c23 100644 --- a/target/i386/kvm/hyperv-stub.c +++ b/target/i386/kvm/hyperv-stub.c @@ -56,3 +56,8 @@ void hyperv_x86_synic_update(X86CPU *cpu) void hyperv_x86_set_vmbus_recommended_features_enabled(void) { } + +uint64_t hyperv_syndbg_query_options(void) +{ + return 0; +} diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 02d3486421..b1f40040f8 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -107,6 +107,10 @@ static bool ptw_setl_slow(const PTETranslate *in, uint32_t old, uint32_t new) { uint32_t cmp; + CPUState *cpu = env_cpu(in->env); + /* We are in cpu_exec, and start_exclusive can't be called directly.*/ + g_assert(cpu->running); + cpu_exec_end(cpu); /* Does x86 really perform a rmw cycle on mmio for ptw? */ start_exclusive(); cmp = cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0); @@ -114,6 +118,7 @@ static bool ptw_setl_slow(const PTETranslate *in, uint32_t old, uint32_t new) cpu_stl_mmuidx_ra(in->env, in->gaddr, new, in->ptw_idx, 0); } end_exclusive(); + cpu_exec_start(cpu); return cmp == old; } diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 945af07a64..2ffac2ed03 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1253,6 +1253,7 @@ struct CPUArchState { /* For SMT processors */ bool has_smt_siblings; int core_index; + int chip_index; #if !defined(CONFIG_USER_ONLY) /* MMU context, only relevant for full system emulation */ @@ -1355,6 +1356,7 @@ struct CPUArchState { * special way (such as routing some resume causes to 0x100, i.e. sreset). */ bool resume_as_sreset; + bool quiesced; #endif /* These resources are used only in TCG */ @@ -1411,8 +1413,10 @@ struct CPUArchState { #define THREAD_SIBLING_FOREACH(cs, cs_sibling) \ CPU_FOREACH(cs_sibling) \ - if (POWERPC_CPU(cs)->env.core_index == \ - POWERPC_CPU(cs_sibling)->env.core_index) + if ((POWERPC_CPU(cs)->env.chip_index == \ + POWERPC_CPU(cs_sibling)->env.chip_index) && \ + (POWERPC_CPU(cs)->env.core_index == \ + POWERPC_CPU(cs_sibling)->env.core_index)) #define SET_FIT_PERIOD(a_, b_, c_, d_) \ do { \ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 70daa5076a..9f811af0a4 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2495,10 +2495,16 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) } } +/* + * system reset is not delivered via normal irq method, so have to set + * halted = 0 to resume CPU running if it was halted. Possibly we should + * move it over to using PPC_INTERRUPT_RESET rather than async_run_on_cpu. + */ void ppc_cpu_do_system_reset(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); + cs->halted = 0; powerpc_excp(cpu, POWERPC_EXCP_RESET); } @@ -2520,6 +2526,7 @@ void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector) /* Anything for nested required here? MSR[HV] bit? */ + cs->halted = 0; powerpc_set_excp_state(cpu, vector, msr); } diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index d8bd5748fa..5041c13962 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -780,7 +780,7 @@ uint32_t HELPER(kxb)(CPUS390XState *env, Int128 a, Int128 b) uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) { - float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status); + float32 ret = float32_muladd(f3, f2, f1, 0, &env->fpu_status); handle_exceptions(env, false, GETPC()); return ret; } @@ -789,7 +789,7 @@ uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) { - float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status); + float64 ret = float64_muladd(f3, f2, f1, 0, &env->fpu_status); handle_exceptions(env, false, GETPC()); return ret; } @@ -798,7 +798,7 @@ uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1, uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) { - float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c, + float32 ret = float32_muladd(f3, f2, f1, float_muladd_negate_c, &env->fpu_status); handle_exceptions(env, false, GETPC()); return ret; @@ -808,7 +808,7 @@ uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1, uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) { - float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c, + float64 ret = float64_muladd(f3, f2, f1, float_muladd_negate_c, &env->fpu_status); handle_exceptions(env, false, GETPC()); return ret; diff --git a/target/s390x/tcg/vec_fpu_helper.c b/target/s390x/tcg/vec_fpu_helper.c index 75cf605b9f..1bbaa82fe8 100644 --- a/target/s390x/tcg/vec_fpu_helper.c +++ b/target/s390x/tcg/vec_fpu_helper.c @@ -621,8 +621,8 @@ static void vfma32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, int i; for (i = 0; i < 4; i++) { - const float32 a = s390_vec_read_float32(v2, i); - const float32 b = s390_vec_read_float32(v3, i); + const float32 a = s390_vec_read_float32(v3, i); + const float32 b = s390_vec_read_float32(v2, i); const float32 c = s390_vec_read_float32(v4, i); float32 ret = float32_muladd(a, b, c, flags, &env->fpu_status); @@ -645,8 +645,8 @@ static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, int i; for (i = 0; i < 2; i++) { - const float64 a = s390_vec_read_float64(v2, i); - const float64 b = s390_vec_read_float64(v3, i); + const float64 a = s390_vec_read_float64(v3, i); + const float64 b = s390_vec_read_float64(v2, i); const float64 c = s390_vec_read_float64(v4, i); const float64 ret = float64_muladd(a, b, c, flags, &env->fpu_status); @@ -664,8 +664,8 @@ static void vfma128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, const S390Vector *v4, CPUS390XState *env, bool s, int flags, uintptr_t retaddr) { - const float128 a = s390_vec_read_float128(v2); - const float128 b = s390_vec_read_float128(v3); + const float128 a = s390_vec_read_float128(v3); + const float128 b = s390_vec_read_float128(v2); const float128 c = s390_vec_read_float128(v4); uint8_t vxc, vec_exc = 0; float128 ret; diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 78ee1ced80..97e4df221a 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -88,7 +88,20 @@ uint32_t simd_desc(uint32_t oprsz, uint32_t maxsz, int32_t data) uint32_t desc = 0; check_size_align(oprsz, maxsz, 0); - tcg_debug_assert(data == sextract32(data, 0, SIMD_DATA_BITS)); + + /* + * We want to check that 'data' will fit into SIMD_DATA_BITS. + * However, some callers want to treat the data as a signed + * value (which they can later get back with simd_data()) + * and some want to treat it as an unsigned value. + * So here we assert only that the data will fit into the + * field in at least one way. This means that some invalid + * values from the caller will not be detected, e.g. if the + * caller wants to handle the value as a signed integer but + * incorrectly passes us 1 << (SIMD_DATA_BITS - 1). + */ + tcg_debug_assert(data == sextract32(data, 0, SIMD_DATA_BITS) || + data == extract32(data, 0, SIMD_DATA_BITS)); oprsz = (oprsz / 8) - 1; maxsz = (maxsz / 8) - 1; diff --git a/tests/avocado/hotplug_blk.py b/tests/avocado/hotplug_blk.py index d55ded1c1d..b36bca02ec 100644 --- a/tests/avocado/hotplug_blk.py +++ b/tests/avocado/hotplug_blk.py @@ -33,7 +33,7 @@ class HotPlug(LinuxTest): 'drive': 'disk', 'id': 'virtio-disk0', 'bus': 'pci.1', - 'addr': 1 + 'addr': '1', } self.assert_no_vda() diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py deleted file mode 100644 index 241ef180af..0000000000 --- a/tests/avocado/machine_aspeed.py +++ /dev/null @@ -1,202 +0,0 @@ -# Functional test that boots the ASPEED SoCs with firmware -# -# Copyright (C) 2022 ASPEED Technology Inc -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# later. See the COPYING file in the top-level directory. - -import time -import os -import tempfile -import subprocess - -from avocado_qemu import LinuxSSHMixIn -from avocado_qemu import QemuSystemTest -from avocado_qemu import wait_for_console_pattern -from avocado_qemu import exec_command -from avocado_qemu import exec_command_and_wait_for_pattern -from avocado_qemu import interrupt_interactive_console_until_pattern -from avocado_qemu import has_cmd -from avocado.utils import archive -from avocado import skipUnless - -class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn): - - EXTRA_BOOTARGS = ( - 'quiet ' - 'systemd.mask=org.openbmc.HostIpmi.service ' - 'systemd.mask=xyz.openbmc_project.Chassis.Control.Power@0.service ' - 'systemd.mask=modprobe@fuse.service ' - 'systemd.mask=rngd.service ' - 'systemd.mask=obmc-console@ttyS2.service ' - ) - - # FIXME: Although these tests boot a whole distro they are still - # slower than comparable machine models. There may be some - # optimisations which bring down the runtime. In the meantime they - # have generous timeouts and are disable for CI which aims for all - # tests to run in less than 60 seconds. - timeout = 240 - - def wait_for_console_pattern(self, success_message, vm=None): - wait_for_console_pattern(self, success_message, - failure_message='Kernel panic - not syncing', - vm=vm) - - def do_test_arm_aspeed_sdk_start(self, image): - self.require_netdev('user') - self.vm.set_console() - self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', - '-net', 'nic', '-net', 'user,hostfwd=:127.0.0.1:0-:22') - self.vm.launch() - - self.wait_for_console_pattern('U-Boot 2019.04') - interrupt_interactive_console_until_pattern( - self, 'Hit any key to stop autoboot:', 'ast#') - exec_command_and_wait_for_pattern( - self, 'setenv bootargs ${bootargs} ' + self.EXTRA_BOOTARGS, 'ast#') - exec_command_and_wait_for_pattern( - self, 'boot', '## Loading kernel from FIT Image') - self.wait_for_console_pattern('Starting kernel ...') - - def do_test_aarch64_aspeed_sdk_start(self, image): - self.vm.set_console() - self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', - '-net', 'nic', '-net', 'user,hostfwd=:127.0.0.1:0-:22') - - self.vm.launch() - - self.wait_for_console_pattern('U-Boot 2023.10') - self.wait_for_console_pattern('## Loading kernel from FIT Image') - self.wait_for_console_pattern('Starting kernel ...') - - @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') - def test_arm_ast2500_evb_sdk(self): - """ - :avocado: tags=arch:arm - :avocado: tags=machine:ast2500-evb - :avocado: tags=flaky - """ - - image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/' - 'download/v08.06/ast2500-default-obmc.tar.gz') - image_hash = ('e1755f3cadff69190438c688d52dd0f0d399b70a1e14b1d3d5540fc4851d38ca') - image_path = self.fetch_asset(image_url, asset_hash=image_hash, - algorithm='sha256') - archive.extract(image_path, self.workdir) - - self.do_test_arm_aspeed_sdk_start( - self.workdir + '/ast2500-default/image-bmc') - self.wait_for_console_pattern('nodistro.0 ast2500-default ttyS4') - - @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') - def test_arm_ast2600_evb_sdk(self): - """ - :avocado: tags=arch:arm - :avocado: tags=machine:ast2600-evb - :avocado: tags=flaky - """ - - image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/' - 'download/v08.06/ast2600-a2-obmc.tar.gz') - image_hash = ('9083506135f622d5e7351fcf7d4e1c7125cee5ba16141220c0ba88931f3681a4') - image_path = self.fetch_asset(image_url, asset_hash=image_hash, - algorithm='sha256') - archive.extract(image_path, self.workdir) - - self.vm.add_args('-device', - 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test'); - self.vm.add_args('-device', - 'ds1338,bus=aspeed.i2c.bus.5,address=0x32'); - self.do_test_arm_aspeed_sdk_start( - self.workdir + '/ast2600-a2/image-bmc') - self.wait_for_console_pattern('nodistro.0 ast2600-a2 ttyS4') - - self.ssh_connect('root', '0penBmc', False) - self.ssh_command('dmesg -c > /dev/null') - - self.ssh_command_output_contains( - 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device ; ' - 'dmesg -c', - 'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d'); - self.ssh_command_output_contains( - 'cat /sys/class/hwmon/hwmon19/temp1_input', '0') - self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', - property='temperature', value=18000); - self.ssh_command_output_contains( - 'cat /sys/class/hwmon/hwmon19/temp1_input', '18000') - - self.ssh_command_output_contains( - 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device ; ' - 'dmesg -c', - 'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32'); - year = time.strftime("%Y") - self.ssh_command_output_contains('/sbin/hwclock -f /dev/rtc1', year); - - def test_aarch64_ast2700_evb_sdk_v09_02(self): - """ - :avocado: tags=arch:aarch64 - :avocado: tags=machine:ast2700-evb - """ - - image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/' - 'download/v09.02/ast2700-default-obmc.tar.gz') - image_hash = 'ac969c2602f4e6bdb69562ff466b89ae3fe1d86e1f6797bb7969d787f82116a7' - image_path = self.fetch_asset(image_url, asset_hash=image_hash, - algorithm='sha256') - archive.extract(image_path, self.workdir) - - num_cpu = 4 - image_dir = self.workdir + '/ast2700-default/' - uboot_size = os.path.getsize(image_dir + 'u-boot-nodtb.bin') - uboot_dtb_load_addr = hex(0x400000000 + uboot_size) - - load_images_list = [ - { - 'addr': '0x400000000', - 'file': image_dir + 'u-boot-nodtb.bin' - }, - { - 'addr': str(uboot_dtb_load_addr), - 'file': image_dir + 'u-boot.dtb' - }, - { - 'addr': '0x430000000', - 'file': image_dir + 'bl31.bin' - }, - { - 'addr': '0x430080000', - 'file': image_dir + 'optee/tee-raw.bin' - } - ] - - for load_image in load_images_list: - addr = load_image['addr'] - file = load_image['file'] - self.vm.add_args('-device', - f'loader,force-raw=on,addr={addr},file={file}') - - for i in range(num_cpu): - self.vm.add_args('-device', - f'loader,addr=0x430000000,cpu-num={i}') - - self.vm.add_args('-smp', str(num_cpu)) - self.vm.add_args('-device', - 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test') - self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc') - self.wait_for_console_pattern('nodistro.0 ast2700-default ttyS12') - - self.ssh_connect('root', '0penBmc', False) - self.ssh_command('dmesg -c > /dev/null') - - self.ssh_command_output_contains( - 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device ' - '&& dmesg -c', - 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d'); - - self.ssh_command_output_contains( - 'cat /sys/class/hwmon/hwmon20/temp1_input', '0') - self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', - property='temperature', value=18000) - self.ssh_command_output_contains( - 'cat /sys/class/hwmon/hwmon20/temp1_input', '18000') diff --git a/tests/avocado/tuxrun_baselines.py b/tests/avocado/tuxrun_baselines.py deleted file mode 100644 index 38064840da..0000000000 --- a/tests/avocado/tuxrun_baselines.py +++ /dev/null @@ -1,224 +0,0 @@ -# Functional test that boots known good tuxboot images the same way -# that tuxrun (www.tuxrun.org) does. This tool is used by things like -# the LKFT project to run regression tests on kernels. -# -# Copyright (c) 2023 Linaro Ltd. -# -# Author: -# Alex Bennée <alex.bennee@linaro.org> -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import os -import time -import tempfile - -from avocado import skip, skipUnless -from avocado_qemu import QemuSystemTest -from avocado_qemu import exec_command, exec_command_and_wait_for_pattern -from avocado_qemu import wait_for_console_pattern -from avocado.utils import process -from avocado.utils.path import find_command - -class TuxRunBaselineTest(QemuSystemTest): - """ - :avocado: tags=accel:tcg - """ - - KERNEL_COMMON_COMMAND_LINE = 'printk.time=0' - # Tests are ~10-40s, allow for --debug/--enable-gcov overhead - timeout = 100 - - def get_tag(self, tagname, default=None): - """ - Get the metadata tag or return the default. - """ - utag = self._get_unique_tag_val(tagname) - print(f"{tagname}/{default} -> {utag}") - if utag: - return utag - - return default - - def setUp(self): - super().setUp() - - # We need zstd for all the tuxrun tests - # See https://github.com/avocado-framework/avocado/issues/5609 - zstd = find_command('zstd', False) - if zstd is False: - self.cancel('Could not find "zstd", which is required to ' - 'decompress rootfs') - self.zstd = zstd - - # Process the TuxRun specific tags, most machines work with - # reasonable defaults but we sometimes need to tweak the - # config. To avoid open coding everything we store all these - # details in the metadata for each test. - - # The tuxboot tag matches the root directory - self.tuxboot = self.get_tag('tuxboot') - - # Most Linux's use ttyS0 for their serial port - self.console = self.get_tag('console', "ttyS0") - - # Does the machine shutdown QEMU nicely on "halt" - self.shutdown = self.get_tag('shutdown') - - # The name of the kernel Image file - self.image = self.get_tag('image', "Image") - - self.root = self.get_tag('root', "vda") - - # Occasionally we need extra devices to hook things up - self.extradev = self.get_tag('extradev') - - self.qemu_img = super().get_qemu_img() - - def wait_for_console_pattern(self, success_message, vm=None): - wait_for_console_pattern(self, success_message, - failure_message='Kernel panic - not syncing', - vm=vm) - - def fetch_tuxrun_assets(self, csums=None, dt=None): - """ - Fetch the TuxBoot assets. They are stored in a standard way so we - use the per-test tags to fetch details. - """ - base_url = f"https://storage.tuxboot.com/20230331/{self.tuxboot}/" - - # empty hash if we weren't passed one - csums = {} if csums is None else csums - ksum = csums.get(self.image, None) - isum = csums.get("rootfs.ext4.zst", None) - - kernel_image = self.fetch_asset(base_url + self.image, - asset_hash = ksum, - algorithm = "sha256") - disk_image_zst = self.fetch_asset(base_url + "rootfs.ext4.zst", - asset_hash = isum, - algorithm = "sha256") - - cmd = f"{self.zstd} -d {disk_image_zst} -o {self.workdir}/rootfs.ext4" - process.run(cmd) - - if dt: - dsum = csums.get(dt, None) - dtb = self.fetch_asset(base_url + dt, - asset_hash = dsum, - algorithm = "sha256") - else: - dtb = None - - return (kernel_image, self.workdir + "/rootfs.ext4", dtb) - - def prepare_run(self, kernel, disk, drive, dtb=None, console_index=0): - """ - Setup to run and add the common parameters to the system - """ - self.vm.set_console(console_index=console_index) - - # all block devices are raw ext4's - blockdev = "driver=raw,file.driver=file," \ - + f"file.filename={disk},node-name=hd0" - - kcmd_line = self.KERNEL_COMMON_COMMAND_LINE - kcmd_line += f" root=/dev/{self.root}" - kcmd_line += f" console={self.console}" - - self.vm.add_args('-kernel', kernel, - '-append', kcmd_line, - '-blockdev', blockdev) - - # Sometimes we need extra devices attached - if self.extradev: - self.vm.add_args('-device', self.extradev) - - self.vm.add_args('-device', - f"{drive},drive=hd0") - - # Some machines need an explicit DTB - if dtb: - self.vm.add_args('-dtb', dtb) - - def run_tuxtest_tests(self, haltmsg): - """ - Wait for the system to boot up, wait for the login prompt and - then do a few things on the console. Trigger a shutdown and - wait to exit cleanly. - """ - self.wait_for_console_pattern("Welcome to TuxTest") - time.sleep(0.2) - exec_command(self, 'root') - time.sleep(0.2) - exec_command(self, 'cat /proc/interrupts') - time.sleep(0.1) - exec_command(self, 'cat /proc/self/maps') - time.sleep(0.1) - exec_command(self, 'uname -a') - time.sleep(0.1) - exec_command_and_wait_for_pattern(self, 'halt', haltmsg) - - # Wait for VM to shut down gracefully if it can - if self.shutdown == "nowait": - self.vm.shutdown() - else: - self.vm.wait() - - def common_tuxrun(self, - csums=None, - dt=None, - drive="virtio-blk-device", - haltmsg="reboot: System halted", - console_index=0): - """ - Common path for LKFT tests. Unless we need to do something - special with the command line we can process most things using - the tag metadata. - """ - (kernel, disk, dtb) = self.fetch_tuxrun_assets(csums, dt) - - self.prepare_run(kernel, disk, drive, dtb, console_index) - self.vm.launch() - self.run_tuxtest_tests(haltmsg) - - - # - # The tests themselves. The configuration is derived from how - # tuxrun invokes qemu (with minor tweaks like using -blockdev - # consistently). The tuxrun equivalent is something like: - # - # tuxrun --device qemu-{ARCH} \ - # --kernel https://storage.tuxboot.com/{TUXBOOT}/{IMAGE} - # - - def test_arm64(self): - """ - :avocado: tags=arch:aarch64 - :avocado: tags=cpu:cortex-a57 - :avocado: tags=machine:virt - :avocado: tags=tuxboot:arm64 - :avocado: tags=console:ttyAMA0 - :avocado: tags=shutdown:nowait - """ - sums = {"Image" : - "ce95a7101a5fecebe0fe630deee6bd97b32ba41bc8754090e9ad8961ea8674c7", - "rootfs.ext4.zst" : - "bbd5ed4b9c7d3f4ca19ba71a323a843c6b585e880115df3b7765769dbd9dd061"} - self.common_tuxrun(csums=sums) - - def test_arm64be(self): - """ - :avocado: tags=arch:aarch64 - :avocado: tags=cpu:cortex-a57 - :avocado: tags=endian:big - :avocado: tags=machine:virt - :avocado: tags=tuxboot:arm64be - :avocado: tags=console:ttyAMA0 - :avocado: tags=shutdown:nowait - """ - sums = { "Image" : - "e0df4425eb2cd9ea9a283e808037f805641c65d8fcecc8f6407d8f4f339561b4", - "rootfs.ext4.zst" : - "e6ffd8813c8a335bc15728f2835f90539c84be7f8f5f691a8b01451b47fb4bd7"} - self.common_tuxrun(csums=sums) diff --git a/tests/data/acpi/x86/pc/DSDT b/tests/data/acpi/x86/pc/DSDT index f68a32e606..8b8235fe79 100644 --- a/tests/data/acpi/x86/pc/DSDT +++ b/tests/data/acpi/x86/pc/DSDT Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.acpierst b/tests/data/acpi/x86/pc/DSDT.acpierst index 0fd79699eb..06829b9c6c 100644 --- a/tests/data/acpi/x86/pc/DSDT.acpierst +++ b/tests/data/acpi/x86/pc/DSDT.acpierst Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.acpihmat b/tests/data/acpi/x86/pc/DSDT.acpihmat index a4dd09e5ef..2fe355ebdb 100644 --- a/tests/data/acpi/x86/pc/DSDT.acpihmat +++ b/tests/data/acpi/x86/pc/DSDT.acpihmat Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.bridge b/tests/data/acpi/x86/pc/DSDT.bridge index 7ef58152d2..4d4067c182 100644 --- a/tests/data/acpi/x86/pc/DSDT.bridge +++ b/tests/data/acpi/x86/pc/DSDT.bridge Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.cphp b/tests/data/acpi/x86/pc/DSDT.cphp index 1079ff81c1..045a52e75b 100644 --- a/tests/data/acpi/x86/pc/DSDT.cphp +++ b/tests/data/acpi/x86/pc/DSDT.cphp Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.dimmpxm b/tests/data/acpi/x86/pc/DSDT.dimmpxm index 34fe3fcad9..205219b99d 100644 --- a/tests/data/acpi/x86/pc/DSDT.dimmpxm +++ b/tests/data/acpi/x86/pc/DSDT.dimmpxm Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.hpbridge b/tests/data/acpi/x86/pc/DSDT.hpbridge index 33c7529f5c..8fa8b519ec 100644 --- a/tests/data/acpi/x86/pc/DSDT.hpbridge +++ b/tests/data/acpi/x86/pc/DSDT.hpbridge Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.hpbrroot b/tests/data/acpi/x86/pc/DSDT.hpbrroot index 2661170c83..01719462a7 100644 --- a/tests/data/acpi/x86/pc/DSDT.hpbrroot +++ b/tests/data/acpi/x86/pc/DSDT.hpbrroot Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.ipmikcs b/tests/data/acpi/x86/pc/DSDT.ipmikcs index 688faf83cb..0ca664688b 100644 --- a/tests/data/acpi/x86/pc/DSDT.ipmikcs +++ b/tests/data/acpi/x86/pc/DSDT.ipmikcs Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.memhp b/tests/data/acpi/x86/pc/DSDT.memhp index 6ede4361f4..03ff464ba4 100644 --- a/tests/data/acpi/x86/pc/DSDT.memhp +++ b/tests/data/acpi/x86/pc/DSDT.memhp Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.nohpet b/tests/data/acpi/x86/pc/DSDT.nohpet index 9d6040733f..b081030f0e 100644 --- a/tests/data/acpi/x86/pc/DSDT.nohpet +++ b/tests/data/acpi/x86/pc/DSDT.nohpet Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.numamem b/tests/data/acpi/x86/pc/DSDT.numamem index aa9986f74b..2c98cafbff 100644 --- a/tests/data/acpi/x86/pc/DSDT.numamem +++ b/tests/data/acpi/x86/pc/DSDT.numamem Binary files differdiff --git a/tests/data/acpi/x86/pc/DSDT.roothp b/tests/data/acpi/x86/pc/DSDT.roothp index 86c2ae11dc..da018dca9e 100644 --- a/tests/data/acpi/x86/pc/DSDT.roothp +++ b/tests/data/acpi/x86/pc/DSDT.roothp Binary files differdiff --git a/tests/data/acpi/x86/q35/APIC.acpihmat-generic-x b/tests/data/acpi/x86/q35/APIC.acpihmat-generic-x new file mode 100644 index 0000000000..317ddb3fbe --- /dev/null +++ b/tests/data/acpi/x86/q35/APIC.acpihmat-generic-x Binary files differdiff --git a/tests/data/acpi/x86/q35/CEDT.acpihmat-generic-x b/tests/data/acpi/x86/q35/CEDT.acpihmat-generic-x new file mode 100644 index 0000000000..31c9011663 --- /dev/null +++ b/tests/data/acpi/x86/q35/CEDT.acpihmat-generic-x Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT b/tests/data/acpi/x86/q35/DSDT index b0bbff7686..fb89ae0ac6 100644 --- a/tests/data/acpi/x86/q35/DSDT +++ b/tests/data/acpi/x86/q35/DSDT Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.acpierst b/tests/data/acpi/x86/q35/DSDT.acpierst index f91cbe55fc..46fd25400b 100644 --- a/tests/data/acpi/x86/q35/DSDT.acpierst +++ b/tests/data/acpi/x86/q35/DSDT.acpierst Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat b/tests/data/acpi/x86/q35/DSDT.acpihmat index 0949fb9d67..61c5bd52a4 100644 --- a/tests/data/acpi/x86/q35/DSDT.acpihmat +++ b/tests/data/acpi/x86/q35/DSDT.acpihmat Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat-generic-x b/tests/data/acpi/x86/q35/DSDT.acpihmat-generic-x new file mode 100644 index 0000000000..497706c974 --- /dev/null +++ b/tests/data/acpi/x86/q35/DSDT.acpihmat-generic-x Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator b/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator index 0fa4daa35c..3aaa2bbdf5 100644 --- a/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator +++ b/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.applesmc b/tests/data/acpi/x86/q35/DSDT.applesmc index a5d032b7d9..944209adea 100644 --- a/tests/data/acpi/x86/q35/DSDT.applesmc +++ b/tests/data/acpi/x86/q35/DSDT.applesmc Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.bridge b/tests/data/acpi/x86/q35/DSDT.bridge index 3464f55297..d9938dba8f 100644 --- a/tests/data/acpi/x86/q35/DSDT.bridge +++ b/tests/data/acpi/x86/q35/DSDT.bridge Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.core-count b/tests/data/acpi/x86/q35/DSDT.core-count index 08f5d5f54b..a24b04cbdb 100644 --- a/tests/data/acpi/x86/q35/DSDT.core-count +++ b/tests/data/acpi/x86/q35/DSDT.core-count Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.core-count2 b/tests/data/acpi/x86/q35/DSDT.core-count2 index d29a7108f8..3a0cb8c581 100644 --- a/tests/data/acpi/x86/q35/DSDT.core-count2 +++ b/tests/data/acpi/x86/q35/DSDT.core-count2 Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.cphp b/tests/data/acpi/x86/q35/DSDT.cphp index 7fd59bf670..20955d0aa3 100644 --- a/tests/data/acpi/x86/q35/DSDT.cphp +++ b/tests/data/acpi/x86/q35/DSDT.cphp Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.cxl b/tests/data/acpi/x86/q35/DSDT.cxl index 613a40b957..3c34d4dcab 100644 --- a/tests/data/acpi/x86/q35/DSDT.cxl +++ b/tests/data/acpi/x86/q35/DSDT.cxl Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.dimmpxm b/tests/data/acpi/x86/q35/DSDT.dimmpxm index 1db0bf454a..228374b55b 100644 --- a/tests/data/acpi/x86/q35/DSDT.dimmpxm +++ b/tests/data/acpi/x86/q35/DSDT.dimmpxm Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.ipmibt b/tests/data/acpi/x86/q35/DSDT.ipmibt index 25f43ae8ef..45f911ada5 100644 --- a/tests/data/acpi/x86/q35/DSDT.ipmibt +++ b/tests/data/acpi/x86/q35/DSDT.ipmibt Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.ipmismbus b/tests/data/acpi/x86/q35/DSDT.ipmismbus index 32bcd25bda..e5d6811bee 100644 --- a/tests/data/acpi/x86/q35/DSDT.ipmismbus +++ b/tests/data/acpi/x86/q35/DSDT.ipmismbus Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.ivrs b/tests/data/acpi/x86/q35/DSDT.ivrs index f91cbe55fc..46fd25400b 100644 --- a/tests/data/acpi/x86/q35/DSDT.ivrs +++ b/tests/data/acpi/x86/q35/DSDT.ivrs Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.memhp b/tests/data/acpi/x86/q35/DSDT.memhp index be90eb71d8..5ce081187a 100644 --- a/tests/data/acpi/x86/q35/DSDT.memhp +++ b/tests/data/acpi/x86/q35/DSDT.memhp Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.mmio64 b/tests/data/acpi/x86/q35/DSDT.mmio64 index 01f276a6af..bdf36c4d57 100644 --- a/tests/data/acpi/x86/q35/DSDT.mmio64 +++ b/tests/data/acpi/x86/q35/DSDT.mmio64 Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.multi-bridge b/tests/data/acpi/x86/q35/DSDT.multi-bridge index 1bd2ee8d2e..1db43a69e4 100644 --- a/tests/data/acpi/x86/q35/DSDT.multi-bridge +++ b/tests/data/acpi/x86/q35/DSDT.multi-bridge Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.noacpihp b/tests/data/acpi/x86/q35/DSDT.noacpihp index 45cc2bcffa..8bc16887e1 100644 --- a/tests/data/acpi/x86/q35/DSDT.noacpihp +++ b/tests/data/acpi/x86/q35/DSDT.noacpihp Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.nohpet b/tests/data/acpi/x86/q35/DSDT.nohpet index f110504b9c..c13e45e361 100644 --- a/tests/data/acpi/x86/q35/DSDT.nohpet +++ b/tests/data/acpi/x86/q35/DSDT.nohpet Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.numamem b/tests/data/acpi/x86/q35/DSDT.numamem index 6090958f39..ba6669437e 100644 --- a/tests/data/acpi/x86/q35/DSDT.numamem +++ b/tests/data/acpi/x86/q35/DSDT.numamem Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.pvpanic-isa b/tests/data/acpi/x86/q35/DSDT.pvpanic-isa index 7a8e568315..6ad42873e9 100644 --- a/tests/data/acpi/x86/q35/DSDT.pvpanic-isa +++ b/tests/data/acpi/x86/q35/DSDT.pvpanic-isa Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.thread-count b/tests/data/acpi/x86/q35/DSDT.thread-count index 08f5d5f54b..a24b04cbdb 100644 --- a/tests/data/acpi/x86/q35/DSDT.thread-count +++ b/tests/data/acpi/x86/q35/DSDT.thread-count Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.thread-count2 b/tests/data/acpi/x86/q35/DSDT.thread-count2 index d29a7108f8..3a0cb8c581 100644 --- a/tests/data/acpi/x86/q35/DSDT.thread-count2 +++ b/tests/data/acpi/x86/q35/DSDT.thread-count2 Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.tis.tpm12 b/tests/data/acpi/x86/q35/DSDT.tis.tpm12 index 29a416f050..e381ce4cbf 100644 --- a/tests/data/acpi/x86/q35/DSDT.tis.tpm12 +++ b/tests/data/acpi/x86/q35/DSDT.tis.tpm12 Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.tis.tpm2 b/tests/data/acpi/x86/q35/DSDT.tis.tpm2 index 59288f02c4..a09253042c 100644 --- a/tests/data/acpi/x86/q35/DSDT.tis.tpm2 +++ b/tests/data/acpi/x86/q35/DSDT.tis.tpm2 Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.type4-count b/tests/data/acpi/x86/q35/DSDT.type4-count index eaca76e8e6..edc23198cd 100644 --- a/tests/data/acpi/x86/q35/DSDT.type4-count +++ b/tests/data/acpi/x86/q35/DSDT.type4-count Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.viot b/tests/data/acpi/x86/q35/DSDT.viot index de0942a13d..4c93dfd5c4 100644 --- a/tests/data/acpi/x86/q35/DSDT.viot +++ b/tests/data/acpi/x86/q35/DSDT.viot Binary files differdiff --git a/tests/data/acpi/x86/q35/DSDT.xapic b/tests/data/acpi/x86/q35/DSDT.xapic index 9059812b58..d4acd851c6 100644 --- a/tests/data/acpi/x86/q35/DSDT.xapic +++ b/tests/data/acpi/x86/q35/DSDT.xapic Binary files differdiff --git a/tests/data/acpi/x86/q35/HMAT.acpihmat-generic-x b/tests/data/acpi/x86/q35/HMAT.acpihmat-generic-x new file mode 100644 index 0000000000..0e5765f6ee --- /dev/null +++ b/tests/data/acpi/x86/q35/HMAT.acpihmat-generic-x Binary files differdiff --git a/tests/data/acpi/x86/q35/SRAT.acpihmat-generic-x b/tests/data/acpi/x86/q35/SRAT.acpihmat-generic-x new file mode 100644 index 0000000000..b45838adb7 --- /dev/null +++ b/tests/data/acpi/x86/q35/SRAT.acpihmat-generic-x Binary files differdiff --git a/tests/functional/meson.build b/tests/functional/meson.build index 758145d1e5..d6d2c0196c 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -11,9 +11,11 @@ endif # Timeouts for individual tests that can be slow e.g. with debugging enabled test_timeouts = { + 'aarch64_aspeed' : 600, 'aarch64_raspi4' : 480, 'aarch64_sbsaref_alpine' : 720, 'aarch64_sbsaref_freebsd' : 720, + 'aarch64_tuxrun' : 240, 'aarch64_virt' : 720, 'acpi_bits' : 420, 'arm_aspeed' : 600, @@ -47,11 +49,13 @@ tests_generic_bsduser = [ ] tests_aarch64_system_thorough = [ + 'aarch64_aspeed', 'aarch64_raspi3', 'aarch64_raspi4', 'aarch64_sbsaref', 'aarch64_sbsaref_alpine', 'aarch64_sbsaref_freebsd', + 'aarch64_tuxrun', 'aarch64_virt', 'multiprocess', ] diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index cbabb1ceed..11c8334a7c 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -78,13 +78,77 @@ def run_cmd(args): def is_readable_executable_file(path): return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK) +# @test: functional test to fail if @failure is seen +# @vm: the VM whose console to process +# @success: a non-None string to look for +# @failure: a string to look for that triggers test failure, or None +# +# Read up to 1 line of text from @vm, looking for @success +# and optionally @failure. +# +# If @success or @failure are seen, immediately return True, +# even if end of line is not yet seen. ie remainder of the +# line is left unread. +# +# If end of line is seen, with neither @success or @failure +# return False +# +# If @failure is seen, then mark @test as failed +def _console_read_line_until_match(test, vm, success, failure): + msg = bytes([]) + done = False + while True: + c = vm.console_socket.recv(1) + if c is None: + done = True + test.fail( + f"EOF in console, expected '{success}'") + break + msg += c + + if success in msg: + done = True + break + if failure and failure in msg: + done = True + vm.console_socket.close() + test.fail( + f"'{failure}' found in console, expected '{success}'") + + if c == b'\n': + break + + console_logger = logging.getLogger('console') + try: + console_logger.debug(msg.decode().strip()) + except: + console_logger.debug(msg) + + return done + def _console_interaction(test, success_message, failure_message, send_string, keep_sending=False, vm=None): assert not keep_sending or send_string + assert success_message or send_string + if vm is None: vm = test.vm - console = vm.console_file - console_logger = logging.getLogger('console') + + test.log.debug( + f"Console interaction: success_msg='{success_message}' " + + f"failure_msg='{failure_message}' send_string='{send_string}'") + + # We'll process console in bytes, to avoid having to + # deal with unicode decode errors from receiving + # partial utf8 byte sequences + success_message_b = None + if success_message is not None: + success_message_b = success_message.encode() + + failure_message_b = None + if failure_message is not None: + failure_message_b = failure_message.encode() + while True: if send_string: vm.console_socket.sendall(send_string.encode()) @@ -92,25 +156,15 @@ def _console_interaction(test, success_message, failure_message, send_string = None # send only once # Only consume console output if waiting for something - if success_message is None and failure_message is None: + if success_message is None: if send_string is None: break continue - try: - msg = console.readline().decode().strip() - except UnicodeDecodeError: - msg = None - if not msg: - continue - console_logger.debug(msg) - if success_message is None or success_message in msg: + if _console_read_line_until_match(test, vm, + success_message_b, + failure_message_b): break - if failure_message and failure_message in msg: - console.close() - fail = 'Failure message found in console: "%s". Expected: "%s"' % \ - (failure_message, success_message) - test.fail(fail) def interrupt_interactive_console_until_pattern(test, success_message, failure_message=None, @@ -135,6 +189,7 @@ def interrupt_interactive_console_until_pattern(test, success_message, :param interrupt_string: a string to send to the console before trying to read a new line """ + assert success_message _console_interaction(test, success_message, failure_message, interrupt_string, True) @@ -149,6 +204,7 @@ def wait_for_console_pattern(test, success_message, failure_message=None, :param success_message: if this message appears, test succeeds :param failure_message: if this message appears, test fails """ + assert success_message _console_interaction(test, success_message, failure_message, None, vm=vm) def exec_command(test, command): @@ -177,6 +233,7 @@ def exec_command_and_wait_for_pattern(test, command, :param success_message: if this message appears, test succeeds :param failure_message: if this message appears, test fails """ + assert success_message _console_interaction(test, success_message, failure_message, command + '\r') def get_qemu_img(test): diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 411978b5ef..90ae59eb54 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -13,8 +13,9 @@ import logging import os -import subprocess import pycotap +import shutil +import subprocess import sys import unittest import uuid @@ -40,11 +41,12 @@ class QemuBaseTest(unittest.TestCase): self.assertIsNotNone(self.qemu_bin, 'QEMU_TEST_QEMU_BINARY must be set') self.arch = self.qemu_bin.split('-')[-1] - self.workdir = os.path.join(BUILD_DIR, 'tests/functional', self.arch, - self.id()) + self.outputdir = os.path.join(BUILD_DIR, 'tests', 'functional', + self.arch, self.id()) + self.workdir = os.path.join(self.outputdir, 'scratch') os.makedirs(self.workdir, exist_ok=True) - self.logdir = self.workdir + self.logdir = self.outputdir self.log_filename = os.path.join(self.logdir, 'base.log') self.log = logging.getLogger('qemu-test') self.log.setLevel(logging.DEBUG) @@ -55,7 +57,15 @@ class QemuBaseTest(unittest.TestCase): self._log_fh.setFormatter(fileFormatter) self.log.addHandler(self._log_fh) + # Capture QEMUMachine logging + self.machinelog = logging.getLogger('qemu.machine') + self.machinelog.setLevel(logging.DEBUG) + self.machinelog.addHandler(self._log_fh) + def tearDown(self): + if "QEMU_TEST_KEEP_SCRATCH" not in os.environ: + shutil.rmtree(self.workdir) + self.machinelog.removeHandler(self._log_fh) self.log.removeHandler(self._log_fh) def main(): @@ -71,10 +81,12 @@ class QemuBaseTest(unittest.TestCase): res = unittest.main(module = None, testRunner = tr, exit = False, argv=["__dummy__", path]) for (test, message) in res.result.errors + res.result.failures: - print('More information on ' + test.id() + ' could be found here:' - '\n %s' % test.log_filename, file=sys.stderr) - if hasattr(test, 'console_log_name'): - print(' %s' % test.console_log_name, file=sys.stderr) + + if hasattr(test, "log_filename"): + print('More information on ' + test.id() + ' could be found here:' + '\n %s' % test.log_filename, file=sys.stderr) + if hasattr(test, 'console_log_name'): + print(' %s' % test.console_log_name, file=sys.stderr) sys.exit(not res.result.wasSuccessful()) @@ -108,7 +120,7 @@ class QemuSystemTest(QemuBaseTest): console_log = logging.getLogger('console') console_log.setLevel(logging.DEBUG) - self.console_log_name = os.path.join(self.workdir, 'console.log') + self.console_log_name = os.path.join(self.logdir, 'console.log') self._console_log_fh = logging.FileHandler(self.console_log_name, mode='w') self._console_log_fh.setLevel(logging.DEBUG) @@ -159,10 +171,19 @@ class QemuSystemTest(QemuBaseTest): self.skipTest('no support for device ' + devicename) def _new_vm(self, name, *args): - vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir) + vm = QEMUMachine(self.qemu_bin, + name=name, + base_temp_dir=self.workdir, + log_dir=self.logdir) self.log.debug('QEMUMachine "%s" created', name) self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir) - self.log.debug('QEMUMachine "%s" log_dir: %s', name, vm.log_dir) + + sockpath = os.environ.get("QEMU_TEST_QMP_BACKDOOR", None) + if sockpath is not None: + vm.add_args("-chardev", + f"socket,id=backdoor,path={sockpath},server=on,wait=off", + "-mon", "chardev=backdoor,mode=control") + if args: vm.add_args(*args) return vm diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py index f05aa96ad7..ab3b27da43 100644 --- a/tests/functional/qemu_test/tuxruntest.py +++ b/tests/functional/qemu_test/tuxruntest.py @@ -39,7 +39,6 @@ class TuxRunBaselineTest(QemuSystemTest): super().setUp() # We need zstd for all the tuxrun tests - # See https://github.com/avocado-framework/avocado/issues/5609 (has_zstd, msg) = has_cmd('zstd') if has_zstd is False: self.skipTest(msg) @@ -125,16 +124,12 @@ class TuxRunBaselineTest(QemuSystemTest): then do a few things on the console. Trigger a shutdown and wait to exit cleanly. """ - self.wait_for_console_pattern("Welcome to TuxTest") - time.sleep(0.2) - exec_command(self, 'root') - time.sleep(0.2) - exec_command(self, 'cat /proc/interrupts') - time.sleep(0.1) - exec_command(self, 'cat /proc/self/maps') - time.sleep(0.1) - exec_command(self, 'uname -a') - time.sleep(0.1) + ps1='root@tuxtest:~#' + self.wait_for_console_pattern('tuxtest login:') + exec_command_and_wait_for_pattern(self, 'root', ps1) + exec_command_and_wait_for_pattern(self, 'cat /proc/interrupts', ps1) + exec_command_and_wait_for_pattern(self, 'cat /proc/self/maps', ps1) + exec_command_and_wait_for_pattern(self, 'uname -a', ps1) exec_command_and_wait_for_pattern(self, 'halt', haltmsg) # Wait for VM to shut down gracefully if it can diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed.py new file mode 100644 index 0000000000..59916efd71 --- /dev/null +++ b/tests/functional/test_aarch64_aspeed.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# +# Functional test that boots the ASPEED SoCs with firmware +# +# Copyright (C) 2022 ASPEED Technology Inc +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import sys +import os + +from qemu_test import QemuSystemTest, Asset +from qemu_test import wait_for_console_pattern +from qemu_test import exec_command_and_wait_for_pattern +from qemu_test.utils import archive_extract + +class AST2x00MachineSDK(QemuSystemTest): + + def do_test_aarch64_aspeed_sdk_start(self, image): + self.require_netdev('user') + self.vm.set_console() + self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', + '-net', 'nic', '-net', 'user', '-snapshot') + + self.vm.launch() + + wait_for_console_pattern(self, 'U-Boot 2023.10') + wait_for_console_pattern(self, '## Loading kernel from FIT Image') + wait_for_console_pattern(self, 'Starting kernel ...') + + ASSET_SDK_V902_AST2700 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.02/ast2700-default-obmc.tar.gz', + 'ac969c2602f4e6bdb69562ff466b89ae3fe1d86e1f6797bb7969d787f82116a7') + + def test_aarch64_ast2700_evb_sdk_v09_02(self): + self.set_machine('ast2700-evb') + + image_path = self.ASSET_SDK_V902_AST2700.fetch() + archive_extract(image_path, self.workdir) + + num_cpu = 4 + image_dir = self.workdir + '/ast2700-default/' + uboot_size = os.path.getsize(image_dir + 'u-boot-nodtb.bin') + uboot_dtb_load_addr = hex(0x400000000 + uboot_size) + + load_images_list = [ + { + 'addr': '0x400000000', + 'file': image_dir + 'u-boot-nodtb.bin' + }, + { + 'addr': str(uboot_dtb_load_addr), + 'file': image_dir + 'u-boot.dtb' + }, + { + 'addr': '0x430000000', + 'file': image_dir + 'bl31.bin' + }, + { + 'addr': '0x430080000', + 'file': image_dir + 'optee/tee-raw.bin' + } + ] + + for load_image in load_images_list: + addr = load_image['addr'] + file = load_image['file'] + self.vm.add_args('-device', + f'loader,force-raw=on,addr={addr},file={file}') + + for i in range(num_cpu): + self.vm.add_args('-device', + f'loader,addr=0x430000000,cpu-num={i}') + + self.vm.add_args('-smp', str(num_cpu)) + self.vm.add_args('-device', + 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test') + self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc') + + wait_for_console_pattern(self, 'ast2700-default login:') + + exec_command_and_wait_for_pattern(self, 'root', 'Password:') + exec_command_and_wait_for_pattern(self, + '0penBmc', 'root@ast2700-default:~#') + + exec_command_and_wait_for_pattern(self, + 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device ', + 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d'); + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon20/temp1_input', '0') + self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000) + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon20/temp1_input', '18000') + + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/test_aarch64_tuxrun.py b/tests/functional/test_aarch64_tuxrun.py new file mode 100755 index 0000000000..75adc8acb8 --- /dev/null +++ b/tests/functional/test_aarch64_tuxrun.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# +# Functional test that boots known good tuxboot images the same way +# that tuxrun (www.tuxrun.org) does. This tool is used by things like +# the LKFT project to run regression tests on kernels. +# +# Copyright (c) 2023 Linaro Ltd. +# +# Author: +# Alex Bennée <alex.bennee@linaro.org> +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import Asset +from qemu_test.tuxruntest import TuxRunBaselineTest + +class TuxRunAarch64Test(TuxRunBaselineTest): + + ASSET_ARM64_KERNEL = Asset( + 'https://storage.tuxboot.com/buildroot/20241119/arm64/Image', + 'b74743c5e89e1cea0f73368d24ae0ae85c5204ff84be3b5e9610417417d2f235') + ASSET_ARM64_ROOTFS = Asset( + 'https://storage.tuxboot.com/buildroot/20241119/arm64/rootfs.ext4.zst', + 'a1acaaae2068df4648d04ff75f532aaa8c5edcd6b936122b6f0db4848a07b465') + + def test_arm64(self): + self.set_machine('virt') + self.cpu='cortex-a57' + self.console='ttyAMA0' + self.wait_for_shutdown=False + self.common_tuxrun(kernel_asset=self.ASSET_ARM64_KERNEL, + rootfs_asset=self.ASSET_ARM64_ROOTFS) + + ASSET_ARM64BE_KERNEL = Asset( + 'https://storage.tuxboot.com/buildroot/20241119/arm64be/Image', + 'fd6af4f16689d17a2c24fe0053cc212edcdf77abdcaf301800b8d38fa9f6e109') + ASSET_ARM64BE_ROOTFS = Asset( + 'https://storage.tuxboot.com/buildroot/20241119/arm64be/rootfs.ext4.zst', + 'f5e9371b62701aab8dead52592ca7488c8a9e255c9be8d7635c7f30f477c2c21') + + def test_arm64be(self): + self.set_machine('virt') + self.cpu='cortex-a57' + self.console='ttyAMA0' + self.wait_for_shutdown=False + self.common_tuxrun(kernel_asset=self.ASSET_ARM64BE_KERNEL, + rootfs_asset=self.ASSET_ARM64BE_ROOTFS) + +if __name__ == '__main__': + TuxRunBaselineTest.main() diff --git a/tests/functional/test_acpi_bits.py b/tests/functional/test_acpi_bits.py index ee40647d5b..e2f84414d7 100755 --- a/tests/functional/test_acpi_bits.py +++ b/tests/functional/test_acpi_bits.py @@ -50,7 +50,7 @@ from typing import ( ) from qemu.machine import QEMUMachine from unittest import skipIf -from qemu_test import QemuBaseTest, Asset +from qemu_test import QemuSystemTest, Asset deps = ["xorriso", "mformat"] # dependent tools needed in the test setup/box. supported_platforms = ['x86_64'] # supported test platforms. @@ -127,7 +127,7 @@ class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods @skipIf(not supported_platform() or missing_deps(), 'unsupported platform or dependencies (%s) not installed' \ % ','.join(deps)) -class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes +class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attributes """ ACPI and SMBIOS tests using biosbits. """ @@ -150,7 +150,6 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._vm = None - self._workDir = None self._baseDir = None self._debugcon_addr = '0x403' @@ -169,7 +168,7 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes config_file = 'bits-cfg.txt' bits_config_dir = os.path.join(self._baseDir, 'acpi-bits', 'bits-config') - target_config_dir = os.path.join(self._workDir, + target_config_dir = os.path.join(self.workdir, 'bits-%d' %self.BITS_INTERNAL_VER, 'boot') self.assertTrue(os.path.exists(bits_config_dir)) @@ -186,7 +185,7 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes bits_test_dir = os.path.join(self._baseDir, 'acpi-bits', 'bits-tests') - target_test_dir = os.path.join(self._workDir, + target_test_dir = os.path.join(self.workdir, 'bits-%d' %self.BITS_INTERNAL_VER, 'boot', 'python') @@ -196,11 +195,12 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes for filename in os.listdir(bits_test_dir): if os.path.isfile(os.path.join(bits_test_dir, filename)) and \ filename.endswith('.py2'): - # all test scripts are named with extension .py2 so that - # avocado does not try to load them. These scripts are - # written for python 2.7 not python 3 and hence if avocado - # loaded them, it would complain about python 3 specific - # syntaxes. + # All test scripts are named with extension .py2 so that + # they are not run by accident. + # + # These scripts are intended to run inside the test VM + # and are written for python 2.7 not python 3, hence + # would cause syntax errors if loaded ouside the VM. newfilename = os.path.splitext(filename)[0] + '.py' shutil.copy2(os.path.join(bits_test_dir, filename), os.path.join(target_test_dir, newfilename)) @@ -224,8 +224,8 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes the directory where we have extracted our pre-built bits grub tarball. """ - grub_x86_64_mods = os.path.join(self._workDir, 'grub-inst-x86_64-efi') - grub_i386_mods = os.path.join(self._workDir, 'grub-inst') + grub_x86_64_mods = os.path.join(self.workdir, 'grub-inst-x86_64-efi') + grub_i386_mods = os.path.join(self.workdir, 'grub-inst') self.assertTrue(os.path.exists(grub_x86_64_mods)) self.assertTrue(os.path.exists(grub_i386_mods)) @@ -246,11 +246,11 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes """ Uses grub-mkrescue to generate a fresh bits iso with the python test scripts """ - bits_dir = os.path.join(self._workDir, + bits_dir = os.path.join(self.workdir, 'bits-%d' %self.BITS_INTERNAL_VER) - iso_file = os.path.join(self._workDir, + iso_file = os.path.join(self.workdir, 'bits-%d.iso' %self.BITS_INTERNAL_VER) - mkrescue_script = os.path.join(self._workDir, + mkrescue_script = os.path.join(self.workdir, 'grub-inst-x86_64-efi', 'bin', 'grub-mkrescue') @@ -284,22 +284,12 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes self.logger.info('iso file %s successfully generated.', iso_file) def setUp(self): # pylint: disable=arguments-differ - super().setUp('qemu-system-') + super().setUp() self.logger = self.log self._baseDir = Path(__file__).parent - # workdir could also be avocado's own workdir in self.workdir. - # At present, I prefer to maintain my own temporary working - # directory. It gives us more control over the generated bits - # log files and also for debugging, we may chose not to remove - # this working directory so that the logs and iso can be - # inspected manually and archived if needed. - self._workDir = tempfile.mkdtemp(prefix='acpi-bits-', - suffix='.tmp') - self.logger.info('working dir: %s', self._workDir) - - prebuiltDir = os.path.join(self._workDir, 'prebuilt') + prebuiltDir = os.path.join(self.workdir, 'prebuilt') if not os.path.isdir(prebuiltDir): os.mkdir(prebuiltDir, mode=0o775) @@ -320,10 +310,10 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes # extract the bits software in the temp working directory with zipfile.ZipFile(bits_zip_file, 'r') as zref: - zref.extractall(self._workDir) + zref.extractall(self.workdir) with tarfile.open(grub_tar_file, 'r', encoding='utf-8') as tarball: - tarball.extractall(self._workDir) + tarball.extractall(self.workdir) self.copy_test_scripts() self.copy_bits_config() @@ -333,7 +323,7 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes """parse the log generated by running bits tests and check for failures. """ - debugconf = os.path.join(self._workDir, self._debugcon_log) + debugconf = os.path.join(self.workdir, self._debugcon_log) log = "" with open(debugconf, 'r', encoding='utf-8') as filehandle: log = filehandle.read() @@ -359,25 +349,19 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes """ if self._vm: self.assertFalse(not self._vm.is_running) - if not os.getenv('BITS_DEBUG') and self._workDir: - self.logger.info('removing the work directory %s', self._workDir) - shutil.rmtree(self._workDir) - else: - self.logger.info('not removing the work directory %s ' \ - 'as BITS_DEBUG is ' \ - 'passed in the environment', self._workDir) super().tearDown() def test_acpi_smbios_bits(self): """The main test case implementation.""" - iso_file = os.path.join(self._workDir, + self.set_machine('pc') + iso_file = os.path.join(self.workdir, 'bits-%d.iso' %self.BITS_INTERNAL_VER) self.assertTrue(os.access(iso_file, os.R_OK)) self._vm = QEMUBitsMachine(binary=self.qemu_bin, - base_temp_dir=self._workDir, + base_temp_dir=self.workdir, debugcon_log=self._debugcon_log, debugcon_addr=self._debugcon_addr) @@ -399,12 +383,10 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes # biosbits has been configured to run all the specified test suites # in batch mode and then automatically initiate a vm shutdown. - # Set timeout to BITS_TIMEOUT for SHUTDOWN event from bits VM at par - # with the avocado test timeout. self._vm.event_wait('SHUTDOWN', timeout=BITS_TIMEOUT) self._vm.wait(timeout=None) self.logger.debug("Checking console output ...") self.parse_log() if __name__ == '__main__': - QemuBaseTest.main() + QemuSystemTest.main() diff --git a/tests/functional/test_arm_aspeed.py b/tests/functional/test_arm_aspeed.py index 5fb1adf464..d88170ac24 100755 --- a/tests/functional/test_arm_aspeed.py +++ b/tests/functional/test_arm_aspeed.py @@ -14,7 +14,6 @@ import tempfile from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern from qemu_test import interrupt_interactive_console_until_pattern -from qemu_test import exec_command from qemu_test import has_cmd from qemu_test.utils import archive_extract from zipfile import ZipFile @@ -136,10 +135,8 @@ class AST2x00Machine(LinuxKernelTest): self.wait_for_console_pattern('lease of 10.0.2.15') # the line before login: self.wait_for_console_pattern(pattern) - time.sleep(0.1) - exec_command(self, 'root') - time.sleep(0.1) - exec_command(self, "passw0rd") + exec_command_and_wait_for_pattern(self, 'root', 'Password:') + exec_command_and_wait_for_pattern(self, 'passw0rd', '#') def do_test_arm_aspeed_buildroot_poweroff(self): exec_command_and_wait_for_pattern(self, 'poweroff', @@ -158,7 +155,7 @@ class AST2x00Machine(LinuxKernelTest): self.vm.add_args('-device', 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test'); self.do_test_arm_aspeed_buildroot_start(image_path, '0x0', - 'Aspeed AST2500 EVB') + 'ast2500-evb login:') exec_command_and_wait_for_pattern(self, 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device', @@ -188,7 +185,8 @@ class AST2x00Machine(LinuxKernelTest): 'ds1338,bus=aspeed.i2c.bus.3,address=0x32'); self.vm.add_args('-device', 'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42'); - self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB') + self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', + 'ast2600-evb login:') exec_command_and_wait_for_pattern(self, 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device', @@ -209,8 +207,8 @@ class AST2x00Machine(LinuxKernelTest): exec_command_and_wait_for_pattern(self, 'echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-3/new_device', 'i2c i2c-3: new_device: Instantiated device slave-24c02 at 0x64'); - exec_command(self, 'i2cset -y 3 0x42 0x64 0x00 0xaa i'); - time.sleep(0.1) + exec_command_and_wait_for_pattern(self, + 'i2cset -y 3 0x42 0x64 0x00 0xaa i', '#'); exec_command_and_wait_for_pattern(self, 'hexdump /sys/bus/i2c/devices/3-1064/slave-eeprom', '0000000 ffaa ffff ffff ffff ffff ffff ffff ffff'); @@ -252,6 +250,74 @@ class AST2x00Machine(LinuxKernelTest): self.do_test_arm_aspeed_buildroot_poweroff() + def do_test_arm_aspeed_sdk_start(self, image): + self.require_netdev('user') + self.vm.set_console() + self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', + '-net', 'nic', '-net', 'user', '-snapshot') + self.vm.launch() + + self.wait_for_console_pattern('U-Boot 2019.04') + self.wait_for_console_pattern('## Loading kernel from FIT Image') + self.wait_for_console_pattern('Starting kernel ...') + + ASSET_SDK_V806_AST2500 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v08.06/ast2500-default-obmc.tar.gz', + 'e1755f3cadff69190438c688d52dd0f0d399b70a1e14b1d3d5540fc4851d38ca') + + def test_arm_ast2500_evb_sdk(self): + self.set_machine('ast2500-evb') + + image_path = self.ASSET_SDK_V806_AST2500.fetch() + + archive_extract(image_path, self.workdir) + + self.do_test_arm_aspeed_sdk_start( + self.workdir + '/ast2500-default/image-bmc') + + self.wait_for_console_pattern('ast2500-default login:') + + ASSET_SDK_V806_AST2600_A2 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v08.06/ast2600-a2-obmc.tar.gz', + '9083506135f622d5e7351fcf7d4e1c7125cee5ba16141220c0ba88931f3681a4') + + def test_arm_ast2600_evb_sdk(self): + self.set_machine('ast2600-evb') + + image_path = self.ASSET_SDK_V806_AST2600_A2.fetch() + + archive_extract(image_path, self.workdir) + + self.vm.add_args('-device', + 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test'); + self.vm.add_args('-device', + 'ds1338,bus=aspeed.i2c.bus.5,address=0x32'); + self.do_test_arm_aspeed_sdk_start( + self.workdir + '/ast2600-a2/image-bmc') + + self.wait_for_console_pattern('ast2600-a2 login:') + + exec_command_and_wait_for_pattern(self, 'root', 'Password:') + exec_command_and_wait_for_pattern(self, '0penBmc', 'root@ast2600-a2:~#') + + exec_command_and_wait_for_pattern(self, + 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device', + 'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d'); + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon19/temp1_input', '0') + self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000); + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon19/temp1_input', '18000') + + exec_command_and_wait_for_pattern(self, + 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device', + 'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32'); + year = time.strftime("%Y") + exec_command_and_wait_for_pattern(self, + '/sbin/hwclock -f /dev/rtc1', year); + + class AST2x00MachineMMC(LinuxKernelTest): ASSET_RAINIER_EMMC = Asset( diff --git a/tests/functional/test_arm_bpim2u.py b/tests/functional/test_arm_bpim2u.py index 2f9fa145e3..35ea58d46c 100755 --- a/tests/functional/test_arm_bpim2u.py +++ b/tests/functional/test_arm_bpim2u.py @@ -37,11 +37,6 @@ class BananaPiMachine(LinuxKernelTest): '5b41b4e11423e562c6011640f9a7cd3bdd0a3d42b83430f7caa70a432e6cd82c') def test_arm_bpim2u(self): - """ - :avocado: tags=arch:arm - :avocado: tags=machine:bpim2u - :avocado: tags=accel:tcg - """ self.set_machine('bpim2u') deb_path = self.ASSET_DEB.fetch() kernel_path = self.extract_from_deb(deb_path, @@ -64,11 +59,6 @@ class BananaPiMachine(LinuxKernelTest): os.remove(dtb_path) def test_arm_bpim2u_initrd(self): - """ - :avocado: tags=arch:arm - :avocado: tags=accel:tcg - :avocado: tags=machine:bpim2u - """ self.set_machine('bpim2u') deb_path = self.ASSET_DEB.fetch() kernel_path = self.extract_from_deb(deb_path, @@ -105,11 +95,6 @@ class BananaPiMachine(LinuxKernelTest): os.remove(initrd_path) def test_arm_bpim2u_gmac(self): - """ - :avocado: tags=arch:arm - :avocado: tags=machine:bpim2u - :avocado: tags=device:sd - """ self.set_machine('bpim2u') self.require_netdev('user') @@ -160,11 +145,6 @@ class BananaPiMachine(LinuxKernelTest): @skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'storage limited') def test_arm_bpim2u_openwrt_22_03_3(self): - """ - :avocado: tags=arch:arm - :avocado: tags=machine:bpim2u - :avocado: tags=device:sd - """ self.set_machine('bpim2u') # This test download a 8.9 MiB compressed image and expand it # to 127 MiB. diff --git a/tests/functional/test_arm_orangepi.py b/tests/functional/test_arm_orangepi.py index d2ed5fcc82..6d57223a03 100755 --- a/tests/functional/test_arm_orangepi.py +++ b/tests/functional/test_arm_orangepi.py @@ -49,11 +49,6 @@ class BananaPiMachine(LinuxKernelTest): '20d3e07dc057e15c12452620e90ecab2047f0f7940d9cba8182ebc795927177f') def test_arm_orangepi(self): - """ - :avocado: tags=arch:arm - :avocado: tags=machine:orangepi-pc - :avocado: tags=accel:tcg - """ self.set_machine('orangepi-pc') deb_path = self.ASSET_DEB.fetch() kernel_path = self.extract_from_deb(deb_path, @@ -75,11 +70,6 @@ class BananaPiMachine(LinuxKernelTest): os.remove(dtb_path) def test_arm_orangepi_initrd(self): - """ - :avocado: tags=arch:arm - :avocado: tags=accel:tcg - :avocado: tags=machine:orangepi-pc - """ self.set_machine('orangepi-pc') deb_path = self.ASSET_DEB.fetch() kernel_path = self.extract_from_deb(deb_path, @@ -115,12 +105,6 @@ class BananaPiMachine(LinuxKernelTest): os.remove(initrd_path) def test_arm_orangepi_sd(self): - """ - :avocado: tags=arch:arm - :avocado: tags=accel:tcg - :avocado: tags=machine:orangepi-pc - :avocado: tags=device:sd - """ self.set_machine('orangepi-pc') self.require_netdev('user') deb_path = self.ASSET_DEB.fetch() @@ -167,11 +151,6 @@ class BananaPiMachine(LinuxKernelTest): @skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'storage limited') def test_arm_orangepi_armbian(self): - """ - :avocado: tags=arch:arm - :avocado: tags=machine:orangepi-pc - :avocado: tags=device:sd - """ self.set_machine('orangepi-pc') # This test download a 275 MiB compressed image and expand it # to 1036 MiB, but the underlying filesystem is 1552 MiB... @@ -208,12 +187,6 @@ class BananaPiMachine(LinuxKernelTest): @skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'storage limited') def test_arm_orangepi_uboot_netbsd9(self): - """ - :avocado: tags=arch:arm - :avocado: tags=machine:orangepi-pc - :avocado: tags=device:sd - :avocado: tags=os:netbsd - """ self.set_machine('orangepi-pc') # This test download a 304MB compressed image and expand it to 2GB deb_path = self.ASSET_UBOOT.fetch() diff --git a/tests/functional/test_arm_sx1.py b/tests/functional/test_arm_sx1.py index 2d86405831..2292317946 100755 --- a/tests/functional/test_arm_sx1.py +++ b/tests/functional/test_arm_sx1.py @@ -44,7 +44,7 @@ class SX1Test(LinuxKernelTest): self.vm.add_args('-no-reboot') self.launch_kernel(zimage_path, initrd=initrd_path) - self.vm.wait() + self.vm.wait(timeout=60) def test_arm_sx1_sd(self): self.set_machine('sx1') @@ -55,7 +55,7 @@ class SX1Test(LinuxKernelTest): self.vm.add_args('-snapshot') self.vm.add_args('-drive', f'format=raw,if=sd,file={sd_fs_path}') self.launch_kernel(zimage_path) - self.vm.wait() + self.vm.wait(timeout=60) def test_arm_sx1_flash(self): self.set_machine('sx1') @@ -66,7 +66,7 @@ class SX1Test(LinuxKernelTest): self.vm.add_args('-snapshot') self.vm.add_args('-drive', f'format=raw,if=pflash,file={flash_path}') self.launch_kernel(zimage_path) - self.vm.wait() + self.vm.wait(timeout=60) if __name__ == '__main__': LinuxKernelTest.main() diff --git a/tests/functional/test_loongarch64_virt.py b/tests/functional/test_loongarch64_virt.py index 2b8baa2c2a..b7d9abf933 100755 --- a/tests/functional/test_loongarch64_virt.py +++ b/tests/functional/test_loongarch64_virt.py @@ -18,16 +18,16 @@ class LoongArchMachine(QemuSystemTest): ASSET_KERNEL = Asset( ('https://github.com/yangxiaojuan-loongson/qemu-binary/' - 'releases/download/2024-05-30/vmlinuz.efi'), + 'releases/download/2024-11-26/vmlinuz.efi'), '08b88a45f48a5fd92260bae895be4e5175be2397481a6f7821b9f39b2965b79e') ASSET_INITRD = Asset( ('https://github.com/yangxiaojuan-loongson/qemu-binary/' - 'releases/download/2024-05-30/ramdisk'), + 'releases/download/2024-11-26/ramdisk'), '03d6fb6f8ee64ecac961120a0bdacf741f17b3bee2141f17fa01908c8baf176a') ASSET_BIOS = Asset( ('https://github.com/yangxiaojuan-loongson/qemu-binary/' - 'releases/download/2024-05-30/QEMU_EFI.fd'), - '937c1e7815e2340150c194a9f8f0474259038a3d7b8845ed62cc08163c46bea1') + 'releases/download/2024-11-26/QEMU_EFI.fd'), + 'f55fbf5d92e885844631ae9bfa8887f659bbb4f6ef2beea9e9ff8bc0603b6697') def wait_for_console_pattern(self, success_message, vm=None): wait_for_console_pattern(self, success_message, diff --git a/tests/functional/test_m68k_nextcube.py b/tests/functional/test_m68k_nextcube.py index 89385a134a..0124622c40 100755 --- a/tests/functional/test_m68k_nextcube.py +++ b/tests/functional/test_m68k_nextcube.py @@ -37,8 +37,7 @@ class NextCubeMachine(QemuSystemTest): 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. + # TODO: wait for the 'displaysurface_create 1120x832' trace-event. time.sleep(2) self.vm.cmd('human-monitor-command', diff --git a/tests/functional/test_mips64el_malta.py b/tests/functional/test_mips64el_malta.py index 6c6355b131..6d1195d362 100755 --- a/tests/functional/test_mips64el_malta.py +++ b/tests/functional/test_mips64el_malta.py @@ -129,7 +129,7 @@ class MaltaMachineFramebuffer(LinuxKernelTest): screendump_path = os.path.join(self.workdir, 'screendump.pbm') kernel_path_gz = self.ASSET_KERNEL_4_7_0.fetch() - kernel_path = self.workdir + "vmlinux" + kernel_path = self.workdir + "/vmlinux" gzip_uncompress(kernel_path_gz, kernel_path) tuxlogo_path = self.ASSET_TUXLOGO.fetch() @@ -159,7 +159,7 @@ class MaltaMachineFramebuffer(LinuxKernelTest): loc = np.where(result >= match_threshold) tuxlogo_count = 0 h, w = tuxlogo_bgr.shape[:2] - debug_png = os.getenv('AVOCADO_CV2_SCREENDUMP_PNG_PATH') + debug_png = os.getenv('QEMU_TEST_CV2_SCREENDUMP_PNG_PATH') for tuxlogo_count, pt in enumerate(zip(*loc[::-1]), start=1): logger.debug('found Tux at position (x, y) = %s', pt) cv2.rectangle(screendump_bgr, pt, diff --git a/tests/functional/test_sh4_tuxrun.py b/tests/functional/test_sh4_tuxrun.py index 352cb360ef..b33533fc7e 100755 --- a/tests/functional/test_sh4_tuxrun.py +++ b/tests/functional/test_sh4_tuxrun.py @@ -15,7 +15,7 @@ import os import time from unittest import skipUnless -from qemu_test import Asset, exec_command_and_wait_for_pattern, exec_command +from qemu_test import Asset, exec_command_and_wait_for_pattern from qemu_test.tuxruntest import TuxRunBaselineTest class TuxRunSh4Test(TuxRunBaselineTest): @@ -27,8 +27,6 @@ class TuxRunSh4Test(TuxRunBaselineTest): 'https://storage.tuxboot.com/20230331/sh4/rootfs.ext4.zst', '3592a7a3d5a641e8b9821449e77bc43c9904a56c30d45da0694349cfd86743fd') - # Note: some segfaults caused by unaligned userspace access - @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable') def test_sh4(self): self.set_machine('r2d') self.cpu='sh7785' @@ -46,10 +44,8 @@ class TuxRunSh4Test(TuxRunBaselineTest): console_index=1) self.vm.launch() - self.wait_for_console_pattern("Welcome to TuxTest") - time.sleep(0.1) - exec_command(self, 'root') - time.sleep(0.1) + self.wait_for_console_pattern("tuxtest login:") + exec_command_and_wait_for_pattern(self, 'root', 'root@tuxtest:~#') exec_command_and_wait_for_pattern(self, 'halt', "reboot: System halted") diff --git a/tests/functional/test_virtio_gpu.py b/tests/functional/test_virtio_gpu.py index 441cbdcf2d..d5027487ac 100755 --- a/tests/functional/test_virtio_gpu.py +++ b/tests/functional/test_virtio_gpu.py @@ -80,9 +80,8 @@ class VirtioGPUx86(QemuSystemTest): self.wait_for_console_pattern("as init process") exec_command_and_wait_for_pattern( - self, "/usr/sbin/modprobe virtio_gpu", "" + self, "/usr/sbin/modprobe virtio_gpu", "features: +virgl +edid" ) - self.wait_for_console_pattern("features: +virgl +edid") def test_vhost_user_vga_virgl(self): # FIXME: should check presence of vhost-user-gpu, virgl, memfd etc diff --git a/tests/functional/test_virtio_version.py b/tests/functional/test_virtio_version.py index eb23060564..92e3f5caf0 100755 --- a/tests/functional/test_virtio_version.py +++ b/tests/functional/test_virtio_version.py @@ -141,6 +141,7 @@ class VirtioVersionCheck(QemuSystemTest): def test_conventional_devs(self): + self.set_machine('pc') self.check_all_variants('virtio-net-pci', VIRTIO_NET) # virtio-blk requires 'driver' parameter #self.check_all_variants('virtio-blk-pci', VIRTIO_BLOCK) @@ -167,6 +168,7 @@ class VirtioVersionCheck(QemuSystemTest): self.assertIn('pci-express-device', ifaces) def test_modern_only_devs(self): + self.set_machine('pc') self.check_modern_only('virtio-vga', VIRTIO_GPU) self.check_modern_only('virtio-gpu-pci', VIRTIO_GPU) self.check_modern_only('virtio-mouse-pci', VIRTIO_INPUT) diff --git a/tests/guest-debug/test_gdbstub.py b/tests/guest-debug/test_gdbstub.py index a715c0e3f5..4f08089e6a 100644 --- a/tests/guest-debug/test_gdbstub.py +++ b/tests/guest-debug/test_gdbstub.py @@ -10,10 +10,16 @@ import traceback fail_count = 0 + +def gdb_exit(status): + gdb.execute(f"exit {status}") + + class arg_parser(argparse.ArgumentParser): def exit(self, status=None, message=""): print("Wrong GDB script test argument! " + message) - gdb.execute("exit 1") + gdb_exit(1) + def report(cond, msg): """Report success/fail of a test""" @@ -38,11 +44,11 @@ def main(test, expected_arch=None): "connected to {}".format(expected_arch)) except (gdb.error, AttributeError): print("SKIP: not connected") - exit(0) + gdb_exit(0) if gdb.parse_and_eval("$pc") == 0: print("SKIP: PC not set") - exit(0) + gdb_exit(0) try: test() @@ -62,4 +68,4 @@ def main(test, expected_arch=None): pass print("All tests complete: {} failures".format(fail_count)) - gdb.execute(f"exit {fail_count}") + gdb_exit(fail_count) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index ea48af4a7b..19817c7353 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1614,10 +1614,13 @@ class ReproducibleStreamWrapper: self.stream.write(arg) class ReproducibleTestRunner(unittest.TextTestRunner): - def __init__(self, stream: Optional[TextIO] = None, - resultclass: Type[unittest.TestResult] = - ReproducibleTestResult, - **kwargs: Any) -> None: + def __init__( + self, + stream: Optional[TextIO] = None, + resultclass: Type[unittest.TextTestResult] = + ReproducibleTestResult, + **kwargs: Any + ) -> None: rstream = ReproducibleStreamWrapper(stream or sys.stdout) super().__init__(stream=rstream, # type: ignore descriptions=True, diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc index 05b75ee59b..c5f4833e45 100644 --- a/tests/qemu-iotests/pylintrc +++ b/tests/qemu-iotests/pylintrc @@ -13,6 +13,7 @@ disable=invalid-name, no-else-return, too-few-public-methods, too-many-arguments, + too-many-positional-arguments, too-many-branches, too-many-lines, too-many-locals, diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index e79f3a03df..16d0ffbdf6 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1936,6 +1936,101 @@ static void test_acpi_q35_tcg_acpi_hmat_noinitiator(void) free_test_data(&data); } +/* Test intended to hit corner cases of SRAT and HMAT */ +static void test_acpi_q35_tcg_acpi_hmat_generic_x(void) +{ + test_data data = {}; + + data.machine = MACHINE_Q35; + data.arch = "x86"; + data.variant = ".acpihmat-generic-x"; + test_acpi_one(" -machine hmat=on,cxl=on" + " -smp 3,sockets=3" + " -m 128M,maxmem=384M,slots=2" + " -device pcie-root-port,chassis=1,id=pci.1" + " -device pci-testdev,bus=pci.1," + "multifunction=on,addr=00.0" + " -device pci-testdev,bus=pci.1,addr=00.1" + " -device pci-testdev,bus=pci.1,id=gidev,addr=00.2" + " -device pxb-cxl,bus_nr=64,bus=pcie.0,id=cxl.1" + " -object memory-backend-ram,size=64M,id=ram0" + " -object memory-backend-ram,size=64M,id=ram1" + " -numa node,nodeid=0,cpus=0,memdev=ram0" + " -numa node,nodeid=1" + " -object acpi-generic-initiator,id=gi0,pci-dev=gidev,node=1" + " -numa node,nodeid=2" + " -object acpi-generic-port,id=gp0,pci-bus=cxl.1,node=2" + " -numa node,nodeid=3,cpus=1" + " -numa node,nodeid=4,memdev=ram1" + " -numa node,nodeid=5,cpus=2" + " -numa hmat-lb,initiator=0,target=0,hierarchy=memory," + "data-type=access-latency,latency=10" + " -numa hmat-lb,initiator=0,target=0,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=800M" + " -numa hmat-lb,initiator=0,target=2,hierarchy=memory," + "data-type=access-latency,latency=100" + " -numa hmat-lb,initiator=0,target=2,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=200M" + " -numa hmat-lb,initiator=0,target=4,hierarchy=memory," + "data-type=access-latency,latency=100" + " -numa hmat-lb,initiator=0,target=4,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=200M" + " -numa hmat-lb,initiator=0,target=5,hierarchy=memory," + "data-type=access-latency,latency=200" + " -numa hmat-lb,initiator=0,target=5,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=400M" + " -numa hmat-lb,initiator=1,target=0,hierarchy=memory," + "data-type=access-latency,latency=500" + " -numa hmat-lb,initiator=1,target=0,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=100M" + " -numa hmat-lb,initiator=1,target=2,hierarchy=memory," + "data-type=access-latency,latency=50" + " -numa hmat-lb,initiator=1,target=2,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=400M" + " -numa hmat-lb,initiator=1,target=4,hierarchy=memory," + "data-type=access-latency,latency=50" + " -numa hmat-lb,initiator=1,target=4,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=800M" + " -numa hmat-lb,initiator=1,target=5,hierarchy=memory," + "data-type=access-latency,latency=500" + " -numa hmat-lb,initiator=1,target=5,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=100M" + " -numa hmat-lb,initiator=3,target=0,hierarchy=memory," + "data-type=access-latency,latency=20" + " -numa hmat-lb,initiator=3,target=0,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=400M" + " -numa hmat-lb,initiator=3,target=2,hierarchy=memory," + "data-type=access-latency,latency=80" + " -numa hmat-lb,initiator=3,target=2,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=200M" + " -numa hmat-lb,initiator=3,target=4,hierarchy=memory," + "data-type=access-latency,latency=80" + " -numa hmat-lb,initiator=3,target=4,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=200M" + " -numa hmat-lb,initiator=3,target=5,hierarchy=memory," + "data-type=access-latency,latency=20" + " -numa hmat-lb,initiator=3,target=5,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=400M" + " -numa hmat-lb,initiator=5,target=0,hierarchy=memory," + "data-type=access-latency,latency=20" + " -numa hmat-lb,initiator=5,target=0,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=400M" + " -numa hmat-lb,initiator=5,target=2,hierarchy=memory," + "data-type=access-latency,latency=80" + " -numa hmat-lb,initiator=5,target=4,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=200M" + " -numa hmat-lb,initiator=5,target=4,hierarchy=memory," + "data-type=access-latency,latency=80" + " -numa hmat-lb,initiator=5,target=2,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=200M" + " -numa hmat-lb,initiator=5,target=5,hierarchy=memory," + "data-type=access-latency,latency=10" + " -numa hmat-lb,initiator=5,target=5,hierarchy=memory," + "data-type=access-bandwidth,bandwidth=800M", + &data); + free_test_data(&data); +} + #ifdef CONFIG_POSIX static void test_acpi_erst(const char *machine, const char *arch) { @@ -2414,6 +2509,8 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/nohpet", test_acpi_q35_tcg_nohpet); qtest_add_func("acpi/q35/acpihmat-noinitiator", test_acpi_q35_tcg_acpi_hmat_noinitiator); + qtest_add_func("acpi/q35/acpihmat-genericx", + test_acpi_q35_tcg_acpi_hmat_generic_x); /* i386 does not support memory hotplug */ if (strcmp(arch, "i386")) { diff --git a/tests/qtest/cmsdk-apb-watchdog-test.c b/tests/qtest/cmsdk-apb-watchdog-test.c index 00b5dbbc81..53538f98c9 100644 --- a/tests/qtest/cmsdk-apb-watchdog-test.c +++ b/tests/qtest/cmsdk-apb-watchdog-test.c @@ -15,14 +15,12 @@ */ #include "qemu/osdep.h" +#include "exec/hwaddr.h" #include "qemu/bitops.h" #include "libqtest-single.h" -/* - * lm3s811evb watchdog; at board startup this runs at 200MHz / 16 == 12.5MHz, - * which is 80ns per tick. - */ #define WDOG_BASE 0x40000000 +#define WDOG_BASE_MPS2 0x40008000 #define WDOGLOAD 0 #define WDOGVALUE 4 @@ -37,39 +35,97 @@ #define SYSDIV_SHIFT 23 #define SYSDIV_LENGTH 4 -static void test_watchdog(void) +#define WDOGLOAD_DEFAULT 0xFFFFFFFF +#define WDOGVALUE_DEFAULT 0xFFFFFFFF + +typedef struct CMSDKAPBWatchdogTestArgs { + int64_t tick; + hwaddr wdog_base; + const char *machine; +} CMSDKAPBWatchdogTestArgs; + +enum { + MACHINE_LM3S811EVB, + MACHINE_MPS2_AN385, +}; + +/* + * lm3s811evb watchdog; at board startup this runs at 200MHz / 16 == 12.5MHz, + * which is 80ns per tick. + * + * IoTKit/ARMSSE dualtimer; driven at 25MHz in mps2-an385, so 40ns per tick + */ +static const CMSDKAPBWatchdogTestArgs machine_info[] = { + [MACHINE_LM3S811EVB] = { + .tick = 80, + .wdog_base = WDOG_BASE, + .machine = "lm3s811evb", + }, + [MACHINE_MPS2_AN385] = { + .tick = 40, + .wdog_base = WDOG_BASE_MPS2, + .machine = "mps2-an385", + }, +}; + +static void system_reset(QTestState *qtest) { - g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0); + QDict *resp; - writel(WDOG_BASE + WDOGCONTROL, 1); - writel(WDOG_BASE + WDOGLOAD, 1000); + resp = qtest_qmp(qtest, "{'execute': 'system_reset'}"); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + qtest_qmp_eventwait(qtest, "RESET"); +} + +static void test_watchdog(const void *ptr) +{ + const CMSDKAPBWatchdogTestArgs *args = ptr; + hwaddr wdog_base = args->wdog_base; + int64_t tick = args->tick; + g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine); + qtest_start(cmdline); + + g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); + + writel(wdog_base + WDOGCONTROL, 1); + writel(wdog_base + WDOGLOAD, 1000); /* Step to just past the 500th tick */ - clock_step(500 * 80 + 1); - g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0); - g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500); + clock_step(500 * tick + 1); + g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500); /* Just past the 1000th tick: timer should have fired */ - clock_step(500 * 80); - g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1); - g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 0); + clock_step(500 * tick); + g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 0); /* VALUE reloads at following tick */ - clock_step(80); - g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000); + clock_step(tick); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000); /* Writing any value to WDOGINTCLR clears the interrupt and reloads */ - clock_step(500 * 80); - g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500); - g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1); - writel(WDOG_BASE + WDOGINTCLR, 0); - g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000); - g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0); + clock_step(500 * tick); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500); + g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1); + writel(wdog_base + WDOGINTCLR, 0); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000); + g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); + + qtest_end(); } -static void test_clock_change(void) +/* + * This test can only be executed in the stellaris board since it relies on a + * component of the board to change the clocking parameters of the watchdog. + */ +static void test_clock_change(const void *ptr) { uint32_t rcc; + const CMSDKAPBWatchdogTestArgs *args = ptr; + g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine); + qtest_start(cmdline); /* * Test that writing to the stellaris board's RCC register to @@ -109,6 +165,201 @@ static void test_clock_change(void) writel(WDOG_BASE + WDOGINTCLR, 0); g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000); g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0); + + qtest_end(); +} + +/* Tests the counter is not running after reset. */ +static void test_watchdog_reset(const void *ptr) +{ + const CMSDKAPBWatchdogTestArgs *args = ptr; + hwaddr wdog_base = args->wdog_base; + int64_t tick = args->tick; + g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine); + qtest_start(cmdline); + g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); + + g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); + g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); + + g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0); + + /* + * The counter should not be running if WDOGCONTROL.INTEN has not been set, + * as it is the case after a cold reset. + */ + clock_step(15 * tick + 1); + g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); + g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); + + /* Let the counter run before reset */ + writel(wdog_base + WDOGLOAD, 3000); + writel(wdog_base + WDOGCONTROL, 1); + + /* Verify it is running */ + clock_step(1000 * tick + 1); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 3000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 2000); + + system_reset(global_qtest); + + /* Check defaults after reset */ + g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); + g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); + + /* The counter should not be running after reset. */ + clock_step(1000 * tick + 1); + g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); + g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); + + qtest_end(); +} + +/* + * Tests inten works as the counter enable based on this description: + * + * Enable the interrupt event, WDOGINT. Set HIGH to enable the counter and the + * interrupt, or LOW to disable the counter and interrupt. Reloads the counter + * from the value in WDOGLOAD when the interrupt is enabled, after previously + * being disabled. + */ +static void test_watchdog_inten(const void *ptr) +{ + const CMSDKAPBWatchdogTestArgs *args = ptr; + hwaddr wdog_base = args->wdog_base; + int64_t tick = args->tick; + g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine); + qtest_start(cmdline); + g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); + + g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); + g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); + + /* + * When WDOGLOAD is written to, the count is immediately restarted from the + * new value. + * + * Note: the counter should not be running as long as WDOGCONTROL.INTEN is + * not set + */ + writel(wdog_base + WDOGLOAD, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000); + clock_step(500 * tick + 1); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000); + + /* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */ + writel(wdog_base + WDOGCONTROL, 1); + clock_step(500 * tick + 1); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500); + + /* or LOW to disable the counter and interrupt. */ + writel(wdog_base + WDOGCONTROL, 0); + clock_step(100 * tick); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500); + + /* + * Reloads the counter from the value in WDOGLOAD when the interrupt is + * enabled, after previously being disabled. + */ + writel(wdog_base + WDOGCONTROL, 1); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000); + + /* Test counter is still on */ + clock_step(50 * tick + 1); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3950); + + /* + * When WDOGLOAD is written to, the count is immediately restarted from the + * new value. + * + * Note: the counter should be running since WDOGCONTROL.INTEN is set + */ + writel(wdog_base + WDOGLOAD, 5000); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 5000); + clock_step(4999 * tick + 1); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1); + g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); + + /* Finally disable and check the conditions don't change */ + writel(wdog_base + WDOGCONTROL, 0); + clock_step(10 * tick); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1); + g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); + + qtest_end(); +} + +/* + * Tests the following custom behavior: + * + * The Luminary version of this device ignores writes to this register after the + * guest has enabled interrupts (so they can only be disabled again via reset). + */ +static void test_watchdog_inten_luminary(const void *ptr) +{ + const CMSDKAPBWatchdogTestArgs *args = ptr; + hwaddr wdog_base = args->wdog_base; + int64_t tick = args->tick; + g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine); + qtest_start(cmdline); + g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); + + g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); + g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); + + /* + * When WDOGLOAD is written to, the count is immediately restarted from the + * new value. + * + * Note: the counter should not be running as long as WDOGCONTROL.INTEN is + * not set + */ + writel(wdog_base + WDOGLOAD, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000); + clock_step(500 * tick + 1); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000); + + /* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */ + writel(wdog_base + WDOGCONTROL, 1); + clock_step(500 * tick + 1); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500); + + /* + * The Luminary version of this device ignores writes to this register after + * the guest has enabled interrupts + */ + writel(wdog_base + WDOGCONTROL, 0); + clock_step(100 * tick); + g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); + g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3400); + g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0x1); + + /* They can only be disabled again via reset */ + system_reset(global_qtest); + + /* Check defaults after reset */ + g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); + g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); + g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0); + + /* The counter should not be running after reset. */ + clock_step(1000 * tick + 1); + g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); + g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); + + qtest_end(); } int main(int argc, char **argv) @@ -116,16 +367,33 @@ int main(int argc, char **argv) int r; g_test_init(&argc, &argv, NULL); + g_test_set_nonfatal_assertions(); - qtest_start("-machine lm3s811evb"); - - qtest_add_func("/cmsdk-apb-watchdog/watchdog", test_watchdog); - qtest_add_func("/cmsdk-apb-watchdog/watchdog_clock_change", - test_clock_change); + if (qtest_has_machine(machine_info[MACHINE_LM3S811EVB].machine)) { + qtest_add_data_func("/cmsdk-apb-watchdog/watchdog", + &machine_info[MACHINE_LM3S811EVB], test_watchdog); + qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_clock_change", + &machine_info[MACHINE_LM3S811EVB], + test_clock_change); + qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_reset", + &machine_info[MACHINE_LM3S811EVB], + test_watchdog_reset); + qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_inten_luminary", + &machine_info[MACHINE_LM3S811EVB], + test_watchdog_inten_luminary); + } + if (qtest_has_machine(machine_info[MACHINE_MPS2_AN385].machine)) { + qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_mps2", + &machine_info[MACHINE_MPS2_AN385], test_watchdog); + qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_reset_mps2", + &machine_info[MACHINE_MPS2_AN385], + test_watchdog_reset); + qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_inten", + &machine_info[MACHINE_MPS2_AN385], + test_watchdog_inten); + } r = g_test_run(); - qtest_end(); - return r; } diff --git a/tests/qtest/libqos/virtio-9p-client.c b/tests/qtest/libqos/virtio-9p-client.c index b8adc8d4b9..98b77db51d 100644 --- a/tests/qtest/libqos/virtio-9p-client.c +++ b/tests/qtest/libqos/virtio-9p-client.c @@ -235,10 +235,11 @@ static const char *rmessage_name(uint8_t id) id == P9_RMKDIR ? "RMKDIR" : id == P9_RLCREATE ? "RLCREATE" : id == P9_RSYMLINK ? "RSYMLINK" : + id == P9_RGETATTR ? "RGETATTR" : id == P9_RLINK ? "RLINK" : id == P9_RUNLINKAT ? "RUNLINKAT" : id == P9_RFLUSH ? "RFLUSH" : - id == P9_RREADDIR ? "READDIR" : + id == P9_RREADDIR ? "RREADDIR" : "<unknown>"; } diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index aa93e98418..f2f35367ae 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -227,7 +227,8 @@ qtests_arm = \ (config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \ (config_all_devices.has_key('CONFIG_CMSDK_APB_DUALTIMER') ? ['cmsdk-apb-dualtimer-test'] : []) + \ (config_all_devices.has_key('CONFIG_CMSDK_APB_TIMER') ? ['cmsdk-apb-timer-test'] : []) + \ - (config_all_devices.has_key('CONFIG_CMSDK_APB_WATCHDOG') ? ['cmsdk-apb-watchdog-test'] : []) + \ + (config_all_devices.has_key('CONFIG_STELLARIS') or + config_all_devices.has_key('CONFIG_MPS2') ? ['cmsdk-apb-watchdog-test'] : []) + \ (config_all_devices.has_key('CONFIG_PFLASH_CFI02') and config_all_devices.has_key('CONFIG_MUSICPAL') ? ['pflash-cfi02-test'] : []) + \ (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed : []) + \ diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c index 0025933883..3f8ba7fa8e 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -140,8 +140,8 @@ static void migrate_set_ports(QTestState *to, QList *channel_list) if (qdict_haskey(addrdict, "port") && qdict_haskey(addr, "port") && (strcmp(qdict_get_str(addrdict, "port"), "0") == 0)) { - addr_port = qdict_get_str(addr, "port"); - qdict_put_str(addrdict, "port", addr_port); + addr_port = qdict_get_str(addr, "port"); + qdict_put_str(addrdict, "port", addr_port); } } diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index e6a2803e71..74d3000198 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -113,8 +113,8 @@ static bool ufd_version_check(void) } uffd_feature_thread_id = api_struct.features & UFFD_FEATURE_THREAD_ID; - ioctl_mask = 1ULL << _UFFDIO_REGISTER | - 1ULL << _UFFDIO_UNREGISTER; + ioctl_mask = (1ULL << _UFFDIO_REGISTER | + 1ULL << _UFFDIO_UNREGISTER); if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) { g_test_message("Skipping test: Missing userfault feature"); return false; @@ -423,7 +423,7 @@ static void migrate_set_parameter_str(QTestState *who, const char *parameter, } static long long migrate_get_parameter_bool(QTestState *who, - const char *parameter) + const char *parameter) { QDict *rsp; int result; @@ -436,7 +436,7 @@ static long long migrate_get_parameter_bool(QTestState *who, } static void migrate_check_parameter_bool(QTestState *who, const char *parameter, - int value) + int value) { int result; @@ -445,7 +445,7 @@ static void migrate_check_parameter_bool(QTestState *who, const char *parameter, } static void migrate_set_parameter_bool(QTestState *who, const char *parameter, - int value) + int value) { qtest_qmp_assert_success(who, "{ 'execute': 'migrate-set-parameters'," @@ -1384,8 +1384,10 @@ static void test_postcopy_preempt_tls_psk(void) static void wait_for_postcopy_status(QTestState *one, const char *status) { wait_for_migration_status(one, status, - (const char * []) { "failed", "active", - "completed", NULL }); + (const char * []) { + "failed", "active", + "completed", NULL + }); } static void postcopy_recover_fail(QTestState *from, QTestState *to, @@ -2575,15 +2577,17 @@ static void test_migrate_fd_finish_hook(QTestState *from, /* Test closing fds */ /* We assume, that QEMU removes named fd from its list, * so this should fail */ - rsp = qtest_qmp(from, "{ 'execute': 'closefd'," - " 'arguments': { 'fdname': 'fd-mig' }}"); + rsp = qtest_qmp(from, + "{ 'execute': 'closefd'," + " 'arguments': { 'fdname': 'fd-mig' }}"); g_assert_true(qdict_haskey(rsp, "error")); error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc"); g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found"); qobject_unref(rsp); - rsp = qtest_qmp(to, "{ 'execute': 'closefd'," - " 'arguments': { 'fdname': 'fd-mig' }}"); + rsp = qtest_qmp(to, + "{ 'execute': 'closefd'," + " 'arguments': { 'fdname': 'fd-mig' }}"); g_assert_true(qdict_haskey(rsp, "error")); error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc"); g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found"); @@ -2741,11 +2745,11 @@ static void test_validate_uri_channels_both_set(void) }, .listen_uri = "defer", .connect_uri = "tcp:127.0.0.1:0", - .connect_channels = "[ { 'channel-type': 'main'," - " 'addr': { 'transport': 'socket'," - " 'type': 'inet'," - " 'host': '127.0.0.1'," - " 'port': '0' } } ]", + .connect_channels = ("[ { ""'channel-type': 'main'," + " 'addr': { 'transport': 'socket'," + " 'type': 'inet'," + " 'host': '127.0.0.1'," + " 'port': '0' } } ]"), }; do_test_validate_uri_channel(&args); @@ -2967,7 +2971,7 @@ test_migrate_precopy_tcp_multifd_qatzip_start(QTestState *from, #ifdef CONFIG_QPL static void * test_migrate_precopy_tcp_multifd_qpl_start(QTestState *from, - QTestState *to) + QTestState *to) { return test_migrate_precopy_tcp_multifd_start_common(from, to, "qpl"); } @@ -3032,11 +3036,11 @@ static void test_multifd_tcp_channels_none(void) .listen_uri = "defer", .start_hook = test_migrate_precopy_tcp_multifd_start, .live = true, - .connect_channels = "[ { 'channel-type': 'main'," - " 'addr': { 'transport': 'socket'," - " 'type': 'inet'," - " 'host': '127.0.0.1'," - " 'port': '0' } } ]", + .connect_channels = ("[ { 'channel-type': 'main'," + " 'addr': { 'transport': 'socket'," + " 'type': 'inet'," + " 'host': '127.0.0.1'," + " 'port': '0' } } ]"), }; test_precopy_common(&args); } @@ -3668,7 +3672,8 @@ static void test_migrate_dirty_limit(void) throttle_us_per_full = 0; while (throttle_us_per_full == 0) { throttle_us_per_full = - read_migrate_property_int(from, "dirty-limit-throttle-time-per-round"); + read_migrate_property_int(from, + "dirty-limit-throttle-time-per-round"); usleep(100); g_assert_false(src_state.stop_seen); } @@ -3680,7 +3685,8 @@ static void test_migrate_dirty_limit(void) /* Check if dirty limit throttle switched off, set timeout 1ms */ do { throttle_us_per_full = - read_migrate_property_int(from, "dirty-limit-throttle-time-per-round"); + read_migrate_property_int(from, + "dirty-limit-throttle-time-per-round"); usleep(100); g_assert_false(src_state.stop_seen); } while (throttle_us_per_full != 0 && --max_try_count); @@ -3709,7 +3715,8 @@ static void test_migrate_dirty_limit(void) throttle_us_per_full = 0; while (throttle_us_per_full == 0) { throttle_us_per_full = - read_migrate_property_int(from, "dirty-limit-throttle-time-per-round"); + read_migrate_property_int(from, + "dirty-limit-throttle-time-per-round"); usleep(100); g_assert_false(src_state.stop_seen); } @@ -3989,7 +3996,7 @@ int main(int argc, char **argv) #endif #ifdef CONFIG_QATZIP migration_test_add("/migration/multifd/tcp/plain/qatzip", - test_multifd_tcp_qatzip); + test_multifd_tcp_qatzip); #endif #ifdef CONFIG_QPL migration_test_add("/migration/multifd/tcp/plain/qpl", diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c index 3c8cd235cf..ab3a12c816 100644 --- a/tests/qtest/virtio-9p-test.c +++ b/tests/qtest/virtio-9p-test.c @@ -693,6 +693,50 @@ static void fs_unlinkat_hardlink(void *obj, void *data, g_assert(stat(real_file, &st_real) == 0); } +static void fs_use_after_unlink(void *obj, void *data, + QGuestAllocator *t_alloc) +{ + QVirtio9P *v9p = obj; + v9fs_set_allocator(t_alloc); + static const uint32_t write_count = P9_MAX_SIZE / 2; + g_autofree char *real_file = virtio_9p_test_path("09/doa_file"); + g_autofree char *buf = g_malloc0(write_count); + struct stat st_file; + struct v9fs_attr attr; + uint32_t fid_file; + uint32_t count; + + tattach({ .client = v9p }); + + /* create a file "09/doa_file" and make sure it exists and is regular */ + tmkdir({ .client = v9p, .atPath = "/", .name = "09" }); + tlcreate({ .client = v9p, .atPath = "09", .name = "doa_file" }); + g_assert(stat(real_file, &st_file) == 0); + g_assert((st_file.st_mode & S_IFMT) == S_IFREG); + + /* request a FID for that regular file that we can work with next */ + fid_file = twalk({ + .client = v9p, .fid = 0, .path = "09/doa_file" + }).newfid; + g_assert(fid_file != 0); + + /* now first open the file in write mode before ... */ + tlopen({ .client = v9p, .fid = fid_file, .flags = O_WRONLY }); + /* ... removing the file from file system */ + tunlinkat({ .client = v9p, .atPath = "09", .name = "doa_file" }); + + /* file is removed, but we still have it open, so this should succeed */ + tgetattr({ + .client = v9p, .fid = fid_file, .request_mask = P9_GETATTR_BASIC, + .rgetattr.attr = &attr + }); + count = twrite({ + .client = v9p, .fid = fid_file, .offset = 0, .count = write_count, + .data = buf + }).count; + g_assert_cmpint(count, ==, write_count); +} + static void cleanup_9p_local_driver(void *data) { /* remove previously created test dir when test is completed */ @@ -758,6 +802,8 @@ static void register_virtio_9p_test(void) qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file, &opts); qos_add_test("local/unlinkat_hardlink", "virtio-9p", fs_unlinkat_hardlink, &opts); + qos_add_test("local/use_after_unlink", "virtio-9p", fs_use_after_unlink, + &opts); } libqos_init(register_virtio_9p_test); diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index 78b83d5575..18d3cf4ae0 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -42,6 +42,9 @@ munmap-pthread: LDFLAGS+=-pthread vma-pthread: CFLAGS+=-pthread vma-pthread: LDFLAGS+=-pthread +sigreturn-sigmask: CFLAGS+=-pthread +sigreturn-sigmask: LDFLAGS+=-pthread + # The vma-pthread seems very sensitive on gitlab and we currently # don't know if its exposing a real bug or the test is flaky. ifneq ($(GITLAB_CI),) diff --git a/tests/tcg/multiarch/gdbstub/interrupt.py b/tests/tcg/multiarch/gdbstub/interrupt.py index 90a45b5140..2d5654d154 100644 --- a/tests/tcg/multiarch/gdbstub/interrupt.py +++ b/tests/tcg/multiarch/gdbstub/interrupt.py @@ -8,7 +8,7 @@ from __future__ import print_function # import gdb -from test_gdbstub import main, report +from test_gdbstub import gdb_exit, main, report def check_interrupt(thread): @@ -49,7 +49,7 @@ def run_test(): """ if len(gdb.selected_inferior().threads()) == 1: print("SKIP: set to run on a single thread") - exit(0) + gdb_exit(0) gdb.execute("set scheduler-locking on") for thread in gdb.selected_inferior().threads(): diff --git a/tests/tcg/multiarch/gdbstub/prot-none.py b/tests/tcg/multiarch/gdbstub/prot-none.py index 7e264589cb..51082a30e4 100644 --- a/tests/tcg/multiarch/gdbstub/prot-none.py +++ b/tests/tcg/multiarch/gdbstub/prot-none.py @@ -5,7 +5,7 @@ This runs as a sourced script (via -x, via run-test.py). SPDX-License-Identifier: GPL-2.0-or-later """ import ctypes -from test_gdbstub import main, report +from test_gdbstub import gdb_exit, main, report def probe_proc_self_mem(): @@ -22,7 +22,7 @@ def run_test(): """Run through the tests one by one""" if not probe_proc_self_mem(): print("SKIP: /proc/self/mem is not usable") - exit(0) + gdb_exit(0) gdb.Breakpoint("break_here") gdb.execute("continue") val = gdb.parse_and_eval("*(char[2] *)q").string() diff --git a/tests/tcg/multiarch/gdbstub/test-proc-mappings.py b/tests/tcg/multiarch/gdbstub/test-proc-mappings.py index 0f687f3284..6eb6ebf7b1 100644 --- a/tests/tcg/multiarch/gdbstub/test-proc-mappings.py +++ b/tests/tcg/multiarch/gdbstub/test-proc-mappings.py @@ -3,7 +3,7 @@ This runs as a sourced script (via -x, via run-test.py).""" from __future__ import print_function import gdb -from test_gdbstub import main, report +from test_gdbstub import gdb_exit, main, report def run_test(): @@ -12,7 +12,7 @@ def run_test(): # m68k GDB supports only GDB_OSABI_SVR4, but GDB_OSABI_LINUX is # required for the info proc support (see set_gdbarch_info_proc()). print("SKIP: m68k GDB does not support GDB_OSABI_LINUX") - exit(0) + gdb_exit(0) mappings = gdb.execute("info proc mappings", False, True) report(isinstance(mappings, str), "Fetched the mappings from the inferior") # Broken with host page size > guest page size diff --git a/tests/tcg/multiarch/sigreturn-sigmask.c b/tests/tcg/multiarch/sigreturn-sigmask.c new file mode 100644 index 0000000000..e6cc904898 --- /dev/null +++ b/tests/tcg/multiarch/sigreturn-sigmask.c @@ -0,0 +1,51 @@ +/* + * Test that sigreturn() does not corrupt the signal mask. + * Block SIGUSR2 and handle SIGUSR1. + * Then sigwait() SIGUSR2, which relies on it remaining blocked. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include <assert.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> + +int seen_sig = -1; + +static void signal_func(int sig) +{ + seen_sig = sig; +} + +static void *thread_func(void *arg) +{ + kill(getpid(), SIGUSR2); + return NULL; +} + +int main(void) +{ + struct sigaction act = { + .sa_handler = signal_func, + }; + pthread_t thread; + sigset_t set; + int sig; + + assert(sigaction(SIGUSR1, &act, NULL) == 0); + + assert(sigemptyset(&set) == 0); + assert(sigaddset(&set, SIGUSR2) == 0); + assert(sigprocmask(SIG_BLOCK, &set, NULL) == 0); + + kill(getpid(), SIGUSR1); + assert(seen_sig == SIGUSR1); + + assert(pthread_create(&thread, NULL, thread_func, NULL) == 0); + assert(sigwait(&set, &sig) == 0); + assert(sig == SIGUSR2); + assert(pthread_join(thread, NULL) == 0); + + return EXIT_SUCCESS; +} diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index 2dab4f4582..da5fe71a40 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -74,8 +74,11 @@ $(Z13_TESTS): CFLAGS+=-march=z13 -O2 TESTS+=$(Z13_TESTS) ifneq ($(CROSS_CC_HAS_Z14),) -Z14_TESTS=vfminmax +Z14_TESTS=fma vfminmax +fma: float.h +fma: LDFLAGS+=-lm vfminmax: LDFLAGS+=-lm +vfminmax: float.h $(Z14_TESTS): CFLAGS+=-march=z14 -O2 TESTS+=$(Z14_TESTS) endif diff --git a/tests/tcg/s390x/float.h b/tests/tcg/s390x/float.h new file mode 100644 index 0000000000..9d1682b8fc --- /dev/null +++ b/tests/tcg/s390x/float.h @@ -0,0 +1,104 @@ +/* + * Helpers for floating-point tests. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef FLOAT_H +#define FLOAT_H + +/* + * Floating-point value classes. + */ +#define N_FORMATS 3 +#define CLASS_MINUS_INF 0 +#define CLASS_MINUS_FN 1 +#define CLASS_MINUS_ZERO 2 +#define CLASS_PLUS_ZERO 3 +#define CLASS_PLUS_FN 4 +#define CLASS_PLUS_INF 5 +#define CLASS_QNAN 6 +#define CLASS_SNAN 7 +#define N_SIGNED_CLASSES 8 +static const size_t float_sizes[N_FORMATS] = { + /* M4 == 2: short */ 4, + /* M4 == 3: long */ 8, + /* M4 == 4: extended */ 16, +}; +static const size_t e_bits[N_FORMATS] = { + /* M4 == 2: short */ 8, + /* M4 == 3: long */ 11, + /* M4 == 4: extended */ 15, +}; +struct float_class { + size_t n; + unsigned char v[2][16]; +}; +static const struct float_class signed_floats[N_FORMATS][N_SIGNED_CLASSES] = { + /* M4 == 2: short */ + { + /* -inf */ {1, {{0xff, 0x80, 0x00, 0x00}}}, + /* -Fn */ {2, {{0xc2, 0x28, 0x00, 0x00}, + {0xc2, 0x29, 0x00, 0x00}}}, + /* -0 */ {1, {{0x80, 0x00, 0x00, 0x00}}}, + /* +0 */ {1, {{0x00, 0x00, 0x00, 0x00}}}, + /* +Fn */ {2, {{0x42, 0x28, 0x00, 0x00}, + {0x42, 0x2a, 0x00, 0x00}}}, + /* +inf */ {1, {{0x7f, 0x80, 0x00, 0x00}}}, + /* QNaN */ {2, {{0x7f, 0xff, 0xff, 0xff}, + {0x7f, 0xff, 0xff, 0xfe}}}, + /* SNaN */ {2, {{0x7f, 0xbf, 0xff, 0xff}, + {0x7f, 0xbf, 0xff, 0xfd}}}, + }, + + /* M4 == 3: long */ + { + /* -inf */ {1, {{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* -Fn */ {2, {{0xc0, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* -0 */ {1, {{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* +0 */ {1, {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* +Fn */ {2, {{0x40, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x40, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* +inf */ {1, {{0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* QNaN */ {2, {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}}}, + /* SNaN */ {2, {{0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd}}}, + }, + + /* M4 == 4: extended */ + { + /* -inf */ {1, {{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* -Fn */ {2, {{0xc0, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0x04, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* -0 */ {1, {{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* +0 */ {1, {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* +Fn */ {2, {{0x40, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x40, 0x04, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* +inf */ {1, {{0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* QNaN */ {2, {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}}}, + /* SNaN */ {2, {{0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd}}}, + }, +}; +static const unsigned char default_nans[N_FORMATS][16] = { + /* M4 == 2: short */ {0x7f, 0xc0, 0x00, 0x00}, + /* M4 == 3: long */ {0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + /* M4 == 4: extended */ {0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +}; + +static void dump_v(FILE *f, const void *v, size_t n) +{ + for (int i = 0; i < n; i++) { + fprintf(f, "%02x", ((const unsigned char *)v)[i]); + } +} + +static void snan_to_qnan(char *v, int fmt) +{ + size_t bit = 1 + e_bits[fmt]; + v[bit / 8] |= 1 << (7 - (bit % 8)); +} + +#endif diff --git a/tests/tcg/s390x/fma.c b/tests/tcg/s390x/fma.c new file mode 100644 index 0000000000..6872f59a7a --- /dev/null +++ b/tests/tcg/s390x/fma.c @@ -0,0 +1,233 @@ +/* + * Test floating-point multiply-and-add instructions. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include <fenv.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "float.h" + +union val { + float e; + double d; + long double x; + char buf[16]; +}; + +/* + * PoP tables as close to the original as possible. + */ +static const char *table1[N_SIGNED_CLASSES][N_SIGNED_CLASSES] = { + /* -inf -Fn -0 +0 +Fn +inf QNaN SNaN */ + {/* -inf */ "P(+inf)", "P(+inf)", "Xi: T(dNaN)", "Xi: T(dNaN)", "P(-inf)", "P(-inf)", "P(b)", "Xi: T(b*)"}, + {/* -Fn */ "P(+inf)", "P(a*b)", "P(+0)", "P(-0)", "P(a*b)", "P(-inf)", "P(b)", "Xi: T(b*)"}, + {/* -0 */ "Xi: T(dNaN)", "P(+0)", "P(+0)", "P(-0)", "P(-0)", "Xi: T(dNaN)", "P(b)", "Xi: T(b*)"}, + {/* +0 */ "Xi: T(dNaN)", "P(-0)", "P(-0)", "P(+0)", "P(+0)", "Xi: T(dNaN)", "P(b)", "Xi: T(b*)"}, + {/* +Fn */ "P(-inf)", "P(a*b)", "P(-0)", "P(+0)", "P(a*b)", "P(+inf)", "P(b)", "Xi: T(b*)"}, + {/* +inf */ "P(-inf)", "P(-inf)", "Xi: T(dNaN)", "Xi: T(dNaN)", "P(+inf)", "P(+inf)", "P(b)", "Xi: T(b*)"}, + {/* QNaN */ "P(a)", "P(a)", "P(a)", "P(a)", "P(a)", "P(a)", "P(a)", "Xi: T(b*)"}, + {/* SNaN */ "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)", "Xi: T(a*)"}, +}; + +static const char *table2[N_SIGNED_CLASSES][N_SIGNED_CLASSES] = { + /* -inf -Fn -0 +0 +Fn +inf QNaN SNaN */ + {/* -inf */ "T(-inf)", "T(-inf)", "T(-inf)", "T(-inf)", "T(-inf)", "Xi: T(dNaN)", "T(c)", "Xi: T(c*)"}, + {/* -Fn */ "T(-inf)", "R(p+c)", "R(p)", "R(p)", "R(p+c)", "T(+inf)", "T(c)", "Xi: T(c*)"}, + {/* -0 */ "T(-inf)", "R(c)", "T(-0)", "Rezd", "R(c)", "T(+inf)", "T(c)", "Xi: T(c*)"}, + {/* +0 */ "T(-inf)", "R(c)", "Rezd", "T(+0)", "R(c)", "T(+inf)", "T(c)", "Xi: T(c*)"}, + {/* +Fn */ "T(-inf)", "R(p+c)", "R(p)", "R(p)", "R(p+c)", "T(+inf)", "T(c)", "Xi: T(c*)"}, + {/* +inf */ "Xi: T(dNaN)", "T(+inf)", "T(+inf)", "T(+inf)", "T(+inf)", "T(+inf)", "T(c)", "Xi: T(c*)"}, + {/* QNaN */ "T(p)", "T(p)", "T(p)", "T(p)", "T(p)", "T(p)", "T(p)", "Xi: T(c*)"}, + /* SNaN: can't happen */ +}; + +static void interpret_tables(union val *r, bool *xi, int fmt, + int cls_a, const union val *a, + int cls_b, const union val *b, + int cls_c, const union val *c) +{ + const char *spec1 = table1[cls_a][cls_b]; + const char *spec2; + union val p; + int cls_p; + + *xi = false; + + if (strcmp(spec1, "P(-inf)") == 0) { + cls_p = CLASS_MINUS_INF; + } else if (strcmp(spec1, "P(+inf)") == 0) { + cls_p = CLASS_PLUS_INF; + } else if (strcmp(spec1, "P(-0)") == 0) { + cls_p = CLASS_MINUS_ZERO; + } else if (strcmp(spec1, "P(+0)") == 0) { + cls_p = CLASS_PLUS_ZERO; + } else if (strcmp(spec1, "P(a)") == 0) { + cls_p = cls_a; + memcpy(&p, a, sizeof(p)); + } else if (strcmp(spec1, "P(b)") == 0) { + cls_p = cls_b; + memcpy(&p, b, sizeof(p)); + } else if (strcmp(spec1, "P(a*b)") == 0) { + /* + * In the general case splitting fma into multiplication and addition + * doesn't work, but this is the case with our test inputs. + */ + cls_p = cls_a == cls_b ? CLASS_PLUS_FN : CLASS_MINUS_FN; + switch (fmt) { + case 0: + p.e = a->e * b->e; + break; + case 1: + p.d = a->d * b->d; + break; + case 2: + p.x = a->x * b->x; + break; + default: + fprintf(stderr, "Unsupported fmt: %d\n", fmt); + exit(1); + } + } else if (strcmp(spec1, "Xi: T(dNaN)") == 0) { + memcpy(r, default_nans[fmt], sizeof(*r)); + *xi = true; + return; + } else if (strcmp(spec1, "Xi: T(a*)") == 0) { + memcpy(r, a, sizeof(*r)); + snan_to_qnan(r->buf, fmt); + *xi = true; + return; + } else if (strcmp(spec1, "Xi: T(b*)") == 0) { + memcpy(r, b, sizeof(*r)); + snan_to_qnan(r->buf, fmt); + *xi = true; + return; + } else { + fprintf(stderr, "Unsupported spec1: %s\n", spec1); + exit(1); + } + + spec2 = table2[cls_p][cls_c]; + if (strcmp(spec2, "T(-inf)") == 0) { + memcpy(r, signed_floats[fmt][CLASS_MINUS_INF].v[0], sizeof(*r)); + } else if (strcmp(spec2, "T(+inf)") == 0) { + memcpy(r, signed_floats[fmt][CLASS_PLUS_INF].v[0], sizeof(*r)); + } else if (strcmp(spec2, "T(-0)") == 0) { + memcpy(r, signed_floats[fmt][CLASS_MINUS_ZERO].v[0], sizeof(*r)); + } else if (strcmp(spec2, "T(+0)") == 0 || strcmp(spec2, "Rezd") == 0) { + memcpy(r, signed_floats[fmt][CLASS_PLUS_ZERO].v[0], sizeof(*r)); + } else if (strcmp(spec2, "R(c)") == 0 || strcmp(spec2, "T(c)") == 0) { + memcpy(r, c, sizeof(*r)); + } else if (strcmp(spec2, "R(p)") == 0 || strcmp(spec2, "T(p)") == 0) { + memcpy(r, &p, sizeof(*r)); + } else if (strcmp(spec2, "R(p+c)") == 0 || strcmp(spec2, "T(p+c)") == 0) { + switch (fmt) { + case 0: + r->e = p.e + c->e; + break; + case 1: + r->d = p.d + c->d; + break; + case 2: + r->x = p.x + c->x; + break; + default: + fprintf(stderr, "Unsupported fmt: %d\n", fmt); + exit(1); + } + } else if (strcmp(spec2, "Xi: T(dNaN)") == 0) { + memcpy(r, default_nans[fmt], sizeof(*r)); + *xi = true; + } else if (strcmp(spec2, "Xi: T(c*)") == 0) { + memcpy(r, c, sizeof(*r)); + snan_to_qnan(r->buf, fmt); + *xi = true; + } else { + fprintf(stderr, "Unsupported spec2: %s\n", spec2); + exit(1); + } +} + +struct iter { + int fmt; + int cls[3]; + int val[3]; +}; + +static bool iter_next(struct iter *it) +{ + int i; + + for (i = 2; i >= 0; i--) { + if (++it->val[i] != signed_floats[it->fmt][it->cls[i]].n) { + return true; + } + it->val[i] = 0; + + if (++it->cls[i] != N_SIGNED_CLASSES) { + return true; + } + it->cls[i] = 0; + } + + return ++it->fmt != N_FORMATS; +} + +int main(void) +{ + int ret = EXIT_SUCCESS; + struct iter it = {}; + + do { + size_t n = float_sizes[it.fmt]; + union val a, b, c, exp, res; + bool xi_exp, xi; + + memcpy(&a, signed_floats[it.fmt][it.cls[0]].v[it.val[0]], sizeof(a)); + memcpy(&b, signed_floats[it.fmt][it.cls[1]].v[it.val[1]], sizeof(b)); + memcpy(&c, signed_floats[it.fmt][it.cls[2]].v[it.val[2]], sizeof(c)); + + interpret_tables(&exp, &xi_exp, it.fmt, + it.cls[1], &b, it.cls[2], &c, it.cls[0], &a); + + memcpy(&res, &a, sizeof(res)); + feclearexcept(FE_ALL_EXCEPT); + switch (it.fmt) { + case 0: + asm("maebr %[a],%[b],%[c]" + : [a] "+f" (res.e) : [b] "f" (b.e), [c] "f" (c.e)); + break; + case 1: + asm("madbr %[a],%[b],%[c]" + : [a] "+f" (res.d) : [b] "f" (b.d), [c] "f" (c.d)); + break; + case 2: + asm("wfmaxb %[a],%[c],%[b],%[a]" + : [a] "+v" (res.x) : [b] "v" (b.x), [c] "v" (c.x)); + break; + default: + fprintf(stderr, "Unsupported fmt: %d\n", it.fmt); + exit(1); + } + xi = fetestexcept(FE_ALL_EXCEPT) == FE_INVALID; + + if (memcmp(&res, &exp, n) != 0 || xi != xi_exp) { + fprintf(stderr, "[ FAILED ] "); + dump_v(stderr, &b, n); + fprintf(stderr, " * "); + dump_v(stderr, &c, n); + fprintf(stderr, " + "); + dump_v(stderr, &a, n); + fprintf(stderr, ": actual="); + dump_v(stderr, &res, n); + fprintf(stderr, "/%d, expected=", (int)xi); + dump_v(stderr, &exp, n); + fprintf(stderr, "/%d\n", (int)xi_exp); + ret = EXIT_FAILURE; + } + } while (iter_next(&it)); + + return ret; +} diff --git a/tests/tcg/s390x/vfminmax.c b/tests/tcg/s390x/vfminmax.c index 22629df160..e66285f762 100644 --- a/tests/tcg/s390x/vfminmax.c +++ b/tests/tcg/s390x/vfminmax.c @@ -4,6 +4,8 @@ #include <stdio.h> #include <string.h> +#include "float.h" + /* * vfmin/vfmax instruction execution. */ @@ -21,99 +23,22 @@ static void vfminmax(unsigned int op, unsigned int m4, unsigned int m5, unsigned int m6, void *v1, const void *v2, const void *v3) { - insn[3] = (m6 << 4) | m5; - insn[4] = (m4 << 4) | 0x0e; - insn[5] = op; + insn[3] = (m6 << 4) | m5; + insn[4] = (m4 << 4) | 0x0e; + insn[5] = op; asm("vl %%v25,%[v2]\n" "vl %%v26,%[v3]\n" "ex 0,%[insn]\n" "vst %%v24,%[v1]\n" : [v1] "=m" (*(char (*)[16])v1) - : [v2] "m" (*(char (*)[16])v2) - , [v3] "m" (*(char (*)[16])v3) - , [insn] "m"(insn) + : [v2] "m" (*(const char (*)[16])v2) + , [v3] "m" (*(const char (*)[16])v3) + , [insn] "m" (insn) : "v24", "v25", "v26"); } /* - * Floating-point value classes. - */ -#define N_FORMATS 3 -#define N_SIGNED_CLASSES 8 -static const size_t float_sizes[N_FORMATS] = { - /* M4 == 2: short */ 4, - /* M4 == 3: long */ 8, - /* M4 == 4: extended */ 16, -}; -static const size_t e_bits[N_FORMATS] = { - /* M4 == 2: short */ 8, - /* M4 == 3: long */ 11, - /* M4 == 4: extended */ 15, -}; -static const unsigned char signed_floats[N_FORMATS][N_SIGNED_CLASSES][2][16] = { - /* M4 == 2: short */ - { - /* -inf */ {{0xff, 0x80, 0x00, 0x00}, - {0xff, 0x80, 0x00, 0x00}}, - /* -Fn */ {{0xc2, 0x28, 0x00, 0x00}, - {0xc2, 0x29, 0x00, 0x00}}, - /* -0 */ {{0x80, 0x00, 0x00, 0x00}, - {0x80, 0x00, 0x00, 0x00}}, - /* +0 */ {{0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00}}, - /* +Fn */ {{0x42, 0x28, 0x00, 0x00}, - {0x42, 0x2a, 0x00, 0x00}}, - /* +inf */ {{0x7f, 0x80, 0x00, 0x00}, - {0x7f, 0x80, 0x00, 0x00}}, - /* QNaN */ {{0x7f, 0xff, 0xff, 0xff}, - {0x7f, 0xff, 0xff, 0xfe}}, - /* SNaN */ {{0x7f, 0xbf, 0xff, 0xff}, - {0x7f, 0xbf, 0xff, 0xfd}}, - }, - - /* M4 == 3: long */ - { - /* -inf */ {{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* -Fn */ {{0xc0, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* -0 */ {{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* +0 */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* +Fn */ {{0x40, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x40, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* +inf */ {{0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* QNaN */ {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}}, - /* SNaN */ {{0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd}}, - }, - - /* M4 == 4: extended */ - { - /* -inf */ {{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* -Fn */ {{0xc0, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0x04, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* -0 */ {{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* +0 */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* +Fn */ {{0x40, 0x04, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x40, 0x04, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* +inf */ {{0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - /* QNaN */ {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}}, - /* SNaN */ {{0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd}}, - }, -}; - -/* * PoP tables as close to the original as possible. */ struct signed_test { @@ -285,13 +210,6 @@ struct signed_test { }, }; -static void dump_v(FILE *f, const void *v, size_t n) -{ - for (int i = 0; i < n; i++) { - fprintf(f, "%02x", ((const unsigned char *)v)[i]); - } -} - static int signed_test(struct signed_test *test, int m4, int m5, const void *v1_exp, bool xi_exp, const void *v2, const void *v3) @@ -320,10 +238,28 @@ static int signed_test(struct signed_test *test, int m4, int m5, return 0; } -static void snan_to_qnan(char *v, int m4) +struct iter { + int cls[2]; + int val[2]; +}; + +static bool iter_next(struct iter *it, int fmt) { - size_t bit = 1 + e_bits[m4 - 2]; - v[bit / 8] |= 1 << (7 - (bit % 8)); + int i; + + for (i = 1; i >= 0; i--) { + if (++it->val[i] != signed_floats[fmt][it->cls[i]].n) { + return true; + } + it->val[i] = 0; + + if (++it->cls[i] != N_SIGNED_CLASSES) { + return true; + } + it->cls[i] = 0; + } + + return false; } int main(void) @@ -333,72 +269,71 @@ int main(void) for (i = 0; i < sizeof(signed_tests) / sizeof(signed_tests[0]); i++) { struct signed_test *test = &signed_tests[i]; - int m4; + int fmt; - for (m4 = 2; m4 <= 4; m4++) { - const unsigned char (*floats)[2][16] = signed_floats[m4 - 2]; - size_t float_size = float_sizes[m4 - 2]; + for (fmt = 0; fmt < N_FORMATS; fmt++) { + size_t float_size = float_sizes[fmt]; + int m4 = fmt + 2; int m5; for (m5 = 0; m5 <= 8; m5 += 8) { char v1_exp[16], v2[16], v3[16]; bool xi_exp = false; + struct iter it = {}; int pos = 0; - int i2; - for (i2 = 0; i2 < N_SIGNED_CLASSES * 2; i2++) { - int i3; + do { + const char *spec = test->table[it.cls[0]][it.cls[1]]; - for (i3 = 0; i3 < N_SIGNED_CLASSES * 2; i3++) { - const char *spec = test->table[i2 / 2][i3 / 2]; + memcpy(&v2[pos], + signed_floats[fmt][it.cls[0]].v[it.val[0]], + float_size); + memcpy(&v3[pos], + signed_floats[fmt][it.cls[1]].v[it.val[1]], + float_size); + if (strcmp(spec, "T(a)") == 0 || + strcmp(spec, "Xi: T(a)") == 0) { + memcpy(&v1_exp[pos], &v2[pos], float_size); + } else if (strcmp(spec, "T(b)") == 0 || + strcmp(spec, "Xi: T(b)") == 0) { + memcpy(&v1_exp[pos], &v3[pos], float_size); + } else if (strcmp(spec, "Xi: T(a*)") == 0) { + memcpy(&v1_exp[pos], &v2[pos], float_size); + snan_to_qnan(&v1_exp[pos], fmt); + } else if (strcmp(spec, "Xi: T(b*)") == 0) { + memcpy(&v1_exp[pos], &v3[pos], float_size); + snan_to_qnan(&v1_exp[pos], fmt); + } else if (strcmp(spec, "T(M(a,b))") == 0) { + /* + * Comparing floats is risky, since the compiler might + * generate the same instruction that we are testing. + * Compare ints instead. This works, because we get + * here only for +-Fn, and the corresponding test + * values have identical exponents. + */ + int v2_int = *(int *)&v2[pos]; + int v3_int = *(int *)&v3[pos]; - memcpy(&v2[pos], floats[i2 / 2][i2 % 2], float_size); - memcpy(&v3[pos], floats[i3 / 2][i3 % 2], float_size); - if (strcmp(spec, "T(a)") == 0 || - strcmp(spec, "Xi: T(a)") == 0) { + if ((v2_int < v3_int) == + ((test->op == VFMIN) != (v2_int < 0))) { memcpy(&v1_exp[pos], &v2[pos], float_size); - } else if (strcmp(spec, "T(b)") == 0 || - strcmp(spec, "Xi: T(b)") == 0) { - memcpy(&v1_exp[pos], &v3[pos], float_size); - } else if (strcmp(spec, "Xi: T(a*)") == 0) { - memcpy(&v1_exp[pos], &v2[pos], float_size); - snan_to_qnan(&v1_exp[pos], m4); - } else if (strcmp(spec, "Xi: T(b*)") == 0) { - memcpy(&v1_exp[pos], &v3[pos], float_size); - snan_to_qnan(&v1_exp[pos], m4); - } else if (strcmp(spec, "T(M(a,b))") == 0) { - /* - * Comparing floats is risky, since the compiler - * might generate the same instruction that we are - * testing. Compare ints instead. This works, - * because we get here only for +-Fn, and the - * corresponding test values have identical - * exponents. - */ - int v2_int = *(int *)&v2[pos]; - int v3_int = *(int *)&v3[pos]; - - if ((v2_int < v3_int) == - ((test->op == VFMIN) != (v2_int < 0))) { - memcpy(&v1_exp[pos], &v2[pos], float_size); - } else { - memcpy(&v1_exp[pos], &v3[pos], float_size); - } } else { - fprintf(stderr, "Unexpected spec: %s\n", spec); - return 1; + memcpy(&v1_exp[pos], &v3[pos], float_size); } - xi_exp |= spec[0] == 'X'; - pos += float_size; + } else { + fprintf(stderr, "Unexpected spec: %s\n", spec); + return 1; + } + xi_exp |= spec[0] == 'X'; + pos += float_size; - if ((m5 & 8) || pos == 16) { - ret |= signed_test(test, m4, m5, - v1_exp, xi_exp, v2, v3); - pos = 0; - xi_exp = false; - } + if ((m5 & 8) || pos == 16) { + ret |= signed_test(test, m4, m5, + v1_exp, xi_exp, v2, v3); + pos = 0; + xi_exp = false; } - } + } while (iter_next(&it, fmt)); if (pos != 0) { ret |= signed_test(test, m4, m5, v1_exp, xi_exp, v2, v3); diff --git a/trace-events b/trace-events index 9cb96f64c4..3ec8a6c720 100644 --- a/trace-events +++ b/trace-events @@ -30,13 +30,6 @@ breakpoint_insert(int cpu_index, uint64_t pc, int flags) "cpu=%d pc=0x%" PRIx64 breakpoint_remove(int cpu_index, uint64_t pc, int flags) "cpu=%d pc=0x%" PRIx64 " flags=0x%x" breakpoint_singlestep(int cpu_index, int enabled) "cpu=%d enable=%d" -# dma-helpers.c -dma_blk_io(void *dbs, void *bs, int64_t offset, bool to_dev) "dbs=%p bs=%p offset=%" PRId64 " to_dev=%d" -dma_aio_cancel(void *dbs) "dbs=%p" -dma_complete(void *dbs, int ret, void *cb) "dbs=%p ret=%d cb=%p" -dma_blk_cb(void *dbs, int ret) "dbs=%p ret=%d" -dma_map_wait(void *dbs) "dbs=%p" - # job.c job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)" job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)" diff --git a/trace/control-target.c b/trace/control-target.c index 97f21e476d..d58e84f6dd 100644 --- a/trace/control-target.c +++ b/trace/control-target.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "qemu/lockable.h" #include "cpu.h" -#include "trace/trace-root.h" #include "trace/control.h" diff --git a/trace/control.c b/trace/control.c index ef107829ac..1c8c50064a 100644 --- a/trace/control.c +++ b/trace/control.c @@ -27,7 +27,6 @@ #include "qemu/error-report.h" #include "qemu/config-file.h" #include "monitor/monitor.h" -#include "trace/trace-root.h" int trace_events_enabled_count; |