diff options
101 files changed, 809 insertions, 277 deletions
diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 7173749c52..d21b4a1fd4 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -494,7 +494,17 @@ check-gprof-gcov: IMAGE: ubuntu2004 MAKE_CHECK_ARGS: check after_script: - - ${CI_PROJECT_DIR}/scripts/ci/coverage-summary.sh + - cd build + - gcovr --xml-pretty --exclude-unreachable-branches --print-summary + -o coverage.xml --root ${CI_PROJECT_DIR} . *.p + coverage: /^\s*lines:\s*\d+.\d+\%/ + artifacts: + name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA} + expire_in: 2 days + reports: + coverage_report: + coverage_format: cobertura + path: build/coverage.xml build-oss-fuzz: extends: .native_build_job_template diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml index d70da61248..634a73a742 100644 --- a/.gitlab-ci.d/cirrus.yml +++ b/.gitlab-ci.d/cirrus.yml @@ -70,19 +70,19 @@ x64-freebsd-13-build: INSTALL_COMMAND: pkg install -y TEST_TARGETS: check -x64-macos-11-base-build: +aarch64-macos-12-base-build: extends: .cirrus_build_job variables: - NAME: macos-11 - CIRRUS_VM_INSTANCE_TYPE: osx_instance + NAME: macos-12 + CIRRUS_VM_INSTANCE_TYPE: macos_instance CIRRUS_VM_IMAGE_SELECTOR: image - CIRRUS_VM_IMAGE_NAME: big-sur-base + CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-monterey-base:latest CIRRUS_VM_CPUS: 12 CIRRUS_VM_RAM: 24G UPDATE_COMMAND: brew update INSTALL_COMMAND: brew install - PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin - PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig + PATH_EXTRA: /opt/homebrew/ccache/libexec:/opt/homebrew/gettext/bin + PKG_CONFIG_PATH: /opt/homebrew/curl/lib/pkgconfig:/opt/homebrew/ncurses/lib/pkgconfig:/opt/homebrew/readline/lib/pkgconfig TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64 diff --git a/.gitlab-ci.d/cirrus/macos-11.vars b/.gitlab-ci.d/cirrus/macos-12.vars index aee9f50de6..ef9e14b373 100644 --- a/.gitlab-ci.d/cirrus/macos-11.vars +++ b/.gitlab-ci.d/cirrus/macos-12.vars @@ -1,16 +1,16 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool variables macos-11 qemu +# $ lcitool variables macos-12 qemu # # https://gitlab.com/libvirt/libvirt-ci -CCACHE='/usr/local/bin/ccache' +CCACHE='/opt/homebrew/bin/ccache' CPAN_PKGS='' CROSS_PKGS='' -MAKE='/usr/local/bin/gmake' -NINJA='/usr/local/bin/ninja' +MAKE='/opt/homebrew/bin/gmake' +NINJA='/opt/homebrew/bin/ninja' PACKAGING_COMMAND='brew' -PIP3='/usr/local/bin/pip3' +PIP3='/opt/homebrew/bin/pip3' PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd' PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme' -PYTHON='/usr/local/bin/python3' +PYTHON='/opt/homebrew/bin/python3' diff --git a/MAINTAINERS b/MAINTAINERS index f3e0a4fc2e..6966490c94 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23,7 +23,7 @@ Descriptions of section entries: W: Web-page with status/info Q: Patchwork web based patch tracking system site T: SCM tree type and location. Type is one of: git, hg, quilt, stgit. - S: Status, one of the following: + S: Status, one of the following (keep in sync with docs/devel/maintainers.rst): Supported: Someone is actually paid to look after this. Maintained: Someone actually looks after it. Odd Fixes: It has a maintainer but they don't have time to do @@ -2005,6 +2005,7 @@ F: docs/interop/vhost-user.rst F: contrib/vhost-user-*/ F: backends/vhost-user.c F: include/sysemu/vhost-user-backend.h +F: subprojects/libvhost-user/ virtio M: Michael S. Tsirkin <mst@redhat.com> @@ -1 +1 @@ -7.1.91 +7.1.93 diff --git a/block/block-backend.c b/block/block-backend.c index b48c91f4e1..d98a96ff37 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2576,14 +2576,25 @@ static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter) bool blk_register_buf(BlockBackend *blk, void *host, size_t size, Error **errp) { + BlockDriverState *bs = blk_bs(blk); + GLOBAL_STATE_CODE(); - return bdrv_register_buf(blk_bs(blk), host, size, errp); + + if (bs) { + return bdrv_register_buf(bs, host, size, errp); + } + return true; } void blk_unregister_buf(BlockBackend *blk, void *host, size_t size) { + BlockDriverState *bs = blk_bs(blk); + GLOBAL_STATE_CODE(); - bdrv_unregister_buf(blk_bs(blk), host, size); + + if (bs) { + bdrv_unregister_buf(bs, host, size); + } } int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, diff --git a/chardev/char-win-stdio.c b/chardev/char-win-stdio.c index a4771ab82e..eb830eabd9 100644 --- a/chardev/char-win-stdio.c +++ b/chardev/char-win-stdio.c @@ -146,6 +146,8 @@ static void qemu_chr_open_stdio(Chardev *chr, bool *be_opened, Error **errp) { + ChardevStdio *opts = backend->u.stdio.data; + bool stdio_allow_signal = !opts->has_signal || opts->signal; WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr); DWORD dwMode; int is_console = 0; @@ -193,7 +195,11 @@ static void qemu_chr_open_stdio(Chardev *chr, if (is_console) { /* set the terminal in raw mode */ /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ - dwMode |= ENABLE_PROCESSED_INPUT; + if (stdio_allow_signal) { + dwMode |= ENABLE_PROCESSED_INPUT; + } else { + dwMode &= ~ENABLE_PROCESSED_INPUT; + } } SetConsoleMode(stdio->hStdIn, dwMode); @@ -1780,7 +1780,7 @@ fi # functions to probe cross compilers container="no" -if test $use_containers = "yes"; then +if test $use_containers = "yes" && (has "docker" || has "podman"); then case $($python "$source_path"/tests/docker/docker.py probe) in *docker) container=docker ;; podman) container=podman ;; diff --git a/docs/devel/acpi-bits.rst b/docs/devel/acpi-bits.rst index 5e22be8ef6..4a94c7d83d 100644 --- a/docs/devel/acpi-bits.rst +++ b/docs/devel/acpi-bits.rst @@ -16,11 +16,8 @@ end user. The other is that we have more control of what we wanted to test and how by directly using acpica interpreter on top of the bios on a running system. More details on the inspiration for developing biosbits and its real life uses can be found in [#a]_ and [#b]_. -This directory contains tests written in python using avocado framework that -exercises the QEMU bios components using biosbits and reports test failures. For QEMU, we maintain a fork of bios bits in gitlab along with all the -dependent submodules: -https://gitlab.com/qemu-project/biosbits-bits +dependent submodules here: https://gitlab.com/qemu-project/biosbits-bits This fork contains numerous fixes, a newer acpica and changes specific to running this avocado QEMU tests using bits. The author of this document is the sole maintainer of the QEMU fork of bios bits repo. @@ -38,10 +35,9 @@ Under ``tests/avocado/`` as the root we have: │ ├── bits-config │ │ └── bits-cfg.txt │ ├── bits-tests - │ │ ├── smbios.py2 - │ │ ├── testacpi.py2 - │ │ └── testcpuid.py2 - │ └── README + │ ├── smbios.py2 + │ ├── testacpi.py2 + │ └── testcpuid.py2 ├── acpi-bits.py * ``tests/avocado``: diff --git a/docs/devel/code-of-conduct.rst b/docs/devel/code-of-conduct.rst index 195444d1b4..f734ed0317 100644 --- a/docs/devel/code-of-conduct.rst +++ b/docs/devel/code-of-conduct.rst @@ -1,3 +1,5 @@ +.. _code_of_conduct: + Code of Conduct =============== diff --git a/docs/devel/index-process.rst b/docs/devel/index-process.rst index d0d7a200fd..d50dd74c3e 100644 --- a/docs/devel/index-process.rst +++ b/docs/devel/index-process.rst @@ -8,6 +8,7 @@ Notes about how to interact with the community and how and where to submit patch code-of-conduct conflict-resolution + maintainers style submitting-a-patch trivial-patches diff --git a/docs/devel/maintainers.rst b/docs/devel/maintainers.rst new file mode 100644 index 0000000000..5c907d901c --- /dev/null +++ b/docs/devel/maintainers.rst @@ -0,0 +1,107 @@ +.. _maintainers: + +The Role of Maintainers +======================= + +Maintainers are a critical part of the project's contributor ecosystem. +They come from a wide range of backgrounds from unpaid hobbyists +working in their spare time to employees who work on the project as +part of their job. Maintainer activities include: + + - reviewing patches and suggesting changes + - collecting patches and preparing pull requests + - tending to the long term health of their area + - participating in other project activities + +They are also human and subject to the same pressures as everyone else +including overload and burnout. Like everyone else they are subject +to project's :ref:`code_of_conduct` and should also be exemplars of +excellent community collaborators. + +The MAINTAINERS file +-------------------- + +The `MAINTAINERS +<https://gitlab.com/qemu-project/qemu/-/blob/master/MAINTAINERS>`__ +file contains the canonical list of who is a maintainer. The file +is machine readable so an appropriately configured git (see +:ref:`cc_the_relevant_maintainer`) can automatically Cc them on +patches that touch their area of code. + +The file also describes the status of the area of code to give an idea +of how actively that section is maintained. + +.. list-table:: Meaning of support status in MAINTAINERS + :widths: 25 75 + :header-rows: 1 + + * - Status + - Meaning + * - Supported + - Someone is actually paid to look after this. + * - Maintained + - Someone actually looks after it. + * - Odd Fixes + - It has a maintainer but they don't have time to do + much other than throw the odd patch in. + * - Orphan + - No current maintainer. + * - Obsolete + - Old obsolete code, should use something else. + +Please bear in mind that even if someone is paid to support something +it does not mean they are paid to support you. This is open source and +the code comes with no warranty and the project makes no guarantees +about dealing with bugs or features requests. + + + +Becoming a reviewer +------------------- + +Most maintainers start by becoming subsystem reviewers. While anyone +is welcome to review code on the mailing list getting added to the +MAINTAINERS file with a line like:: + + R: Random Hacker <rhacker@example.com> + +marks you as a 'designated reviewer' - expected to provide regular +spontaneous feedback. This will ensure that patches touching a given +subsystem will automatically be CC'd to you. + +Becoming a maintainer +--------------------- + +Maintainers are volunteers who put themselves forward or have been +asked by others to keep an eye on an area of code. They have generally +demonstrated to the community, usually via contributions and code +reviews, that they have a good understanding of the subsystem. They +are also trusted to make a positive contribution to the project and +work well with the other contributors. + +The process is simple - simply send a patch to the list that updates +the ``MAINTAINERS`` file. Sometimes this is done as part of a larger +series when a new sub-system is being added to the code base. This can +also be done by a retiring maintainer who nominates their replacement +after discussion with other contributors. + +Once the patch is reviewed and merged the only other step is to make +sure your GPG key is signed. + +.. _maintainer_keys: + +Maintainer GPG Keys +~~~~~~~~~~~~~~~~~~~ + +GPG is used to sign pull requests so they can be identified as really +coming from the maintainer. If your key is not already signed by +members of the QEMU community, you should make arrangements to attend +a `KeySigningParty <https://wiki.qemu.org/KeySigningParty>`__ (for +example at KVM Forum) or make alternative arrangements to have your +key signed by an attendee. Key signing requires meeting another +community member **in person** [#]_ so please make appropriate +arrangements. + +.. [#] In recent pandemic times we have had to exercise some + flexibility here. Maintainers still need to sign their pull + requests though. diff --git a/docs/devel/submitting-a-patch.rst b/docs/devel/submitting-a-patch.rst index fec33ce148..c641d948f1 100644 --- a/docs/devel/submitting-a-patch.rst +++ b/docs/devel/submitting-a-patch.rst @@ -3,34 +3,27 @@ Submitting a Patch ================== -QEMU welcomes contributions of code (either fixing bugs or adding new -functionality). However, we get a lot of patches, and so we have some -guidelines about submitting patches. If you follow these, you'll help -make our task of code review easier and your patch is likely to be -committed faster. +QEMU welcomes contributions to fix bugs, add functionality or improve +the documentation. However, we get a lot of patches, and so we have +some guidelines about submitting them. If you follow these, you'll +help make our task of contribution review easier and your change is +likely to be accepted and committed faster. This page seems very long, so if you are only trying to post a quick one-shot fix, the bare minimum we ask is that: -- You **must** provide a Signed-off-by: line (this is a hard - requirement because it's how you say "I'm legally okay to contribute - this and happy for it to go into QEMU", modeled after the `Linux kernel - <http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/SubmittingPatches?id=f6f94e2ab1b33f0082ac22d71f66385a60d8157f#n297>`__ - policy.) ``git commit -s`` or ``git format-patch -s`` will add one. -- All contributions to QEMU must be **sent as patches** to the - qemu-devel `mailing list <https://wiki.qemu.org/Contribute/MailingLists>`__. - Patch contributions should not be posted on the bug tracker, posted on - forums, or externally hosted and linked to. (We have other mailing lists too, - but all patches must go to qemu-devel, possibly with a Cc: to another - list.) ``git send-email`` (`step-by-step setup - guide <https://git-send-email.io/>`__ and `hints and - tips <https://elixir.bootlin.com/linux/latest/source/Documentation/process/email-clients.rst>`__) - works best for delivering the patch without mangling it, but - attachments can be used as a last resort on a first-time submission. -- You must read replies to your message, and be willing to act on them. - Note, however, that maintainers are often willing to manually fix up - first-time contributions, since there is a learning curve involved in - making an ideal patch submission. +.. list-table:: Minimal Checklist for Patches + :widths: 35 65 + :header-rows: 1 + + * - Check + - Reason + * - Patches contain Signed-off-by: Real Name <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` + * - Be prepared to respond to review comments + - Code that doesn't pass review will not get merged. See :ref:`participating_in_code_review` You do not have to subscribe to post (list policy is to reply-to-all to preserve CCs and keep non-subscribers in the loop on the threads they @@ -229,6 +222,19 @@ bisection doesn't land on a known-broken state. Submitting your Patches ----------------------- +The QEMU project uses a public email based workflow for reviewing and +merging patches. As a result all contributions to QEMU must be **sent +as patches** to the qemu-devel `mailing list +<https://wiki.qemu.org/Contribute/MailingLists>`__. Patch +contributions should not be posted on the bug tracker, posted on +forums, or externally hosted and linked to. (We have other mailing +lists too, but all patches must go to qemu-devel, possibly with a Cc: +to another list.) ``git send-email`` (`step-by-step setup guide +<https://git-send-email.io/>`__ and `hints and tips +<https://elixir.bootlin.com/linux/latest/source/Documentation/process/email-clients.rst>`__) +works best for delivering the patch without mangling it, but +attachments can be used as a last resort on a first-time submission. + .. _if_you_cannot_send_patch_emails: If you cannot send patch emails @@ -314,10 +320,12 @@ git repository to fetch the original commit. Patch emails must include a ``Signed-off-by:`` line ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For more information see `SubmittingPatches 1.12 -<http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/SubmittingPatches?id=f6f94e2ab1b33f0082ac22d71f66385a60d8157f#n297>`__. -This is vital or we will not be able to apply your patch! Please use -your real name to sign a patch (not an alias or acronym). +Your patches **must** include a Signed-off-by: line. This is a hard +requirement because it's how you say "I'm legally okay to contribute +this and happy for it to go into QEMU". The process is modelled after +the `Linux kernel +<http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/SubmittingPatches?id=f6f94e2ab1b33f0082ac22d71f66385a60d8157f#n297>`__ +policy. If you wrote the patch, make sure your "From:" and "Signed-off-by:" lines use the same spelling. It's okay if you subscribe or contribute to @@ -327,6 +335,11 @@ include a "From:" line in the body of the email (different from your envelope From:) that will give credit to the correct author; but again, that author's Signed-off-by: line is mandatory, with the same spelling. +There are various tooling options for automatically adding these tags +include using ``git commit -s`` or ``git format-patch -s``. For more +information see `SubmittingPatches 1.12 +<http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/SubmittingPatches?id=f6f94e2ab1b33f0082ac22d71f66385a60d8157f#n297>`__. + .. _include_a_meaningful_cover_letter: Include a meaningful cover letter @@ -397,9 +410,19 @@ Participating in Code Review ---------------------------- All patches submitted to the QEMU project go through a code review -process before they are accepted. Some areas of code that are well -maintained may review patches quickly, lesser-loved areas of code may -have a longer delay. +process before they are accepted. This will often mean a series will +go through a number of iterations before being picked up by +:ref:`maintainers<maintainers>`. You therefore should be prepared to +read replies to your messages and be willing to act on them. + +Maintainers are often willing to manually fix up first-time +contributions, since there is a learning curve involved in making an +ideal patch submission. However for the best results you should +proactively respond to suggestions with changes or justifications for +your current approach. + +Some areas of code that are well maintained may review patches +quickly, lesser-loved areas of code may have a longer delay. .. _stay_around_to_fix_problems_raised_in_code_review: @@ -411,14 +434,20 @@ developers will identify bugs, or suggest a cleaner approach, or even just point out code style issues or commit message typos. You'll need to respond to these, and then send a second version of your patches with the issues fixed. This takes a little time and effort on your part, but -if you don't do it then your changes will never get into QEMU. It's also -just polite -- it is quite disheartening for a developer to spend time -reviewing your code and suggesting improvements, only to find that -you're not going to do anything further and it was all wasted effort. +if you don't do it then your changes will never get into QEMU. + +Remember that a maintainer is under no obligation to take your +patches. If someone has spent the time reviewing your code and +suggesting improvements and you simply re-post without either +addressing the comment directly or providing additional justification +for the change then it becomes wasted effort. You cannot demand others +merge and then fix up your code after the fact. When replying to comments on your patches **reply to all and not just the sender** -- keeping discussion on the mailing list means everybody -can follow it. +can follow it. Remember the spirit of the :ref:`code_of_conduct` and +keep discussions respectful and collaborative and avoid making +personal comments. .. _pay_attention_to_review_comments: diff --git a/docs/devel/submitting-a-pull-request.rst b/docs/devel/submitting-a-pull-request.rst index c9d1e8afd9..a4cd7ebbb6 100644 --- a/docs/devel/submitting-a-pull-request.rst +++ b/docs/devel/submitting-a-pull-request.rst @@ -53,14 +53,10 @@ series) and that "make check" passes before sending out the pull request. As a submaintainer you're one of QEMU's lines of defense against bad code, so double check the details. -**All pull requests must be signed**. If your key is not already signed -by members of the QEMU community, you should make arrangements to attend -a `KeySigningParty <https://wiki.qemu.org/KeySigningParty>`__ (for -example at KVM Forum) or make alternative arrangements to have your key -signed by an attendee. Key signing requires meeting another community -member \*in person\* so please make appropriate arrangements. By -"signed" here we mean that the pullreq email should quote a tag which is -a GPG-signed tag (as created with 'gpg tag -s ...'). +**All pull requests must be signed**. By "signed" here we mean that +the pullreq email should quote a tag which is a GPG-signed tag (as +created with 'gpg tag -s ...'). See :ref:`maintainer_keys` for +details. **Pull requests not for master should say "not for master" and have "PULL SUBSYSTEM whatever" in the subject tag**. If your pull request is diff --git a/docs/system/s390x/bootdevices.rst b/docs/system/s390x/bootdevices.rst index b5950133e8..1a7a18b43b 100644 --- a/docs/system/s390x/bootdevices.rst +++ b/docs/system/s390x/bootdevices.rst @@ -53,6 +53,32 @@ recommended to specify a CD-ROM device via ``-device scsi-cd`` (as mentioned above) instead. +Selecting kernels with the ``loadparm`` property +------------------------------------------------ + +The ``s390-ccw-virtio`` machine supports the so-called ``loadparm`` parameter +which can be used to select the kernel on the disk of the guest that the +s390-ccw bios should boot. When starting QEMU, it can be specified like this:: + + qemu-system-s390x -machine s390-ccw-virtio,loadparm=<string> + +The first way to use this parameter is to use the word ``PROMPT`` as the +``<string>`` here. In that case the s390-ccw bios will show a list of +installed kernels on the disk of the guest and ask the user to enter a number +to chose which kernel should be booted -- similar to what can be achieved by +specifying the ``-boot menu=on`` option when starting QEMU. Note that the menu +list will only show the names of the installed kernels when using a DASD-like +disk image with 4k byte sectors. On normal SCSI-style disks with 512-byte +sectors, there is not enough space for the zipl loader on the disk to store +the kernel names, so you only get a list without names here. + +The second way to use this parameter is to use a number in the range from 0 +to 31. The numbers that can be used here correspond to the numbers that are +shown when using the ``PROMPT`` option, and the s390-ccw bios will then try +to automatically boot the kernel that is associated with the given number. +Note that ``0`` can be used to boot the default entry. + + Booting from a network device ----------------------------- diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index f38117057b..b9ed231fe8 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -220,8 +220,6 @@ struct IntelHDAReg { void (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg); }; -static void intel_hda_reset(DeviceState *dev); - /* --------------------------------------------------------------------- */ static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase) @@ -516,7 +514,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) { if ((d->g_ctl & ICH6_GCTL_RESET) == 0) { - intel_hda_reset(DEVICE(d)); + device_cold_reset(DEVICE(d)); } } @@ -1083,11 +1081,9 @@ static void intel_hda_reset(DeviceState *dev) intel_hda_regs_reset(d); d->wall_base_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - /* reset codecs */ QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) { DeviceState *qdev = kid->child; cdev = HDA_CODEC_DEVICE(qdev); - device_legacy_reset(DEVICE(cdev)); d->state_sts |= (1 << cdev->cad); } intel_hda_update_irq(d); diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c index 68bfa47568..35c38f6252 100644 --- a/hw/display/qxl-logger.c +++ b/hw/display/qxl-logger.c @@ -106,7 +106,7 @@ static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) QXLImage *image; QXLImageDescriptor *desc; - image = qxl_phys2virt(qxl, addr, group_id); + image = qxl_phys2virt(qxl, addr, group_id, sizeof(QXLImage)); if (!image) { return 1; } @@ -214,7 +214,8 @@ int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) cmd->u.set.position.y, cmd->u.set.visible ? "yes" : "no", cmd->u.set.shape); - cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id); + cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id, + sizeof(QXLCursor)); if (!cursor) { return 1; } @@ -236,6 +237,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) { bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT; void *data; + size_t datasz; int ret; if (!qxl->cmdlog) { @@ -247,7 +249,20 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) qxl_name(qxl_type, ext->cmd.type), compat ? "(compat)" : ""); - data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + switch (ext->cmd.type) { + case QXL_CMD_DRAW: + datasz = compat ? sizeof(QXLCompatDrawable) : sizeof(QXLDrawable); + break; + case QXL_CMD_SURFACE: + datasz = sizeof(QXLSurfaceCmd); + break; + case QXL_CMD_CURSOR: + datasz = sizeof(QXLCursorCmd); + break; + default: + goto out; + } + data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, datasz); if (!data) { return 1; } @@ -269,6 +284,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) qxl_log_cmd_cursor(qxl, data, ext->group_id); break; } +out: fprintf(stderr, "\n"); return 0; } diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c index ca217004bf..fcfd40c3ac 100644 --- a/hw/display/qxl-render.c +++ b/hw/display/qxl-render.c @@ -107,7 +107,9 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.resized = 0; qxl->guest_primary.data = qxl_phys2virt(qxl, qxl->guest_primary.surface.mem, - MEMSLOT_GROUP_GUEST); + MEMSLOT_GROUP_GUEST, + qxl->guest_primary.abs_stride + * height); if (!qxl->guest_primary.data) { goto end; } @@ -228,7 +230,8 @@ static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl, if (offset == size) { return; } - chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id); + chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id, + sizeof(QXLDataChunk) + chunk->data_size); if (!chunk) { return; } @@ -295,7 +298,8 @@ fail: /* called from spice server thread context only */ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) { - QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, + sizeof(QXLCursorCmd)); QXLCursor *cursor; QEMUCursor *c; @@ -314,7 +318,15 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) } switch (cmd->type) { case QXL_CURSOR_SET: - cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id); + /* First read the QXLCursor to get QXLDataChunk::data_size ... */ + cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id, + sizeof(QXLCursor)); + if (!cursor) { + return 1; + } + /* Then read including the chunked data following QXLCursor. */ + cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id, + sizeof(QXLCursor) + cursor->chunk.data_size); if (!cursor) { return 1; } diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 5b10f697f1..6772849dec 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -274,7 +274,8 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) QXL_IO_MONITORS_CONFIG_ASYNC)); } - cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST); + cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST, + sizeof(QXLMonitorsConfig)); if (cfg != NULL && cfg->count == 1) { qxl->guest_primary.resized = 1; qxl->guest_head0_width = cfg->heads[0].width; @@ -459,7 +460,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) switch (le32_to_cpu(ext->cmd.type)) { case QXL_CMD_SURFACE: { - QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, + sizeof(QXLSurfaceCmd)); if (!cmd) { return 1; @@ -494,7 +496,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) } case QXL_CMD_CURSOR: { - QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, + sizeof(QXLCursorCmd)); if (!cmd) { return 1; @@ -1381,6 +1384,7 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, qxl_set_guest_bug(d, "%s: pci_region = %d", __func__, pci_region); return 1; } + assert(guest_end - pci_start <= memory_region_size(mr)); virt_start = (intptr_t)memory_region_get_ram_ptr(mr); memslot.slot_id = slot_id; @@ -1421,11 +1425,13 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) /* can be also called from spice server thread context */ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, - uint32_t *s, uint64_t *o) + uint32_t *s, uint64_t *o, + size_t size_requested) { uint64_t phys = le64_to_cpu(pqxl); uint32_t slot = (phys >> (64 - 8)) & 0xff; uint64_t offset = phys & 0xffffffffffff; + uint64_t size_available; if (slot >= NUM_MEMSLOTS) { qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot, @@ -1449,6 +1455,23 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, slot, offset, qxl->guest_slots[slot].size); return false; } + size_available = memory_region_size(qxl->guest_slots[slot].mr); + if (qxl->guest_slots[slot].offset + offset >= size_available) { + qxl_set_guest_bug(qxl, + "slot %d offset %"PRIu64" > region size %"PRIu64"\n", + slot, qxl->guest_slots[slot].offset + offset, + size_available); + return false; + } + size_available -= qxl->guest_slots[slot].offset + offset; + if (size_requested > size_available) { + qxl_set_guest_bug(qxl, + "slot %d offset %"PRIu64" size %zu: " + "overrun by %"PRIu64" bytes\n", + slot, offset, size_requested, + size_requested - size_available); + return false; + } *s = slot; *o = offset; @@ -1456,7 +1479,8 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, } /* can be also called from spice server thread context */ -void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) +void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id, + size_t size) { uint64_t offset; uint32_t slot; @@ -1467,7 +1491,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) offset = le64_to_cpu(pqxl) & 0xffffffffffff; return (void *)(intptr_t)offset; case MEMSLOT_GROUP_GUEST: - if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset)) { + if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size)) { return NULL; } ptr = memory_region_get_ram_ptr(qxl->guest_slots[slot].mr); @@ -1933,9 +1957,9 @@ static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, uint32_t slot; bool rc; - rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset); - assert(rc == true); size = (uint64_t)height * abs(stride); + rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size); + assert(rc == true); trace_qxl_surfaces_dirty(qxl->id, offset, size); qxl_set_dirty(qxl->guest_slots[slot].mr, qxl->guest_slots[slot].offset + offset, @@ -1964,7 +1988,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) } cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], - MEMSLOT_GROUP_GUEST); + MEMSLOT_GROUP_GUEST, sizeof(QXLSurfaceCmd)); assert(cmd); assert(cmd->type == QXL_SURFACE_CMD_CREATE); qxl_dirty_one_surface(qxl, cmd->u.surface_create.data, diff --git a/hw/display/qxl.h b/hw/display/qxl.h index e74de9579d..7894bd5134 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -147,7 +147,28 @@ OBJECT_DECLARE_SIMPLE_TYPE(PCIQXLDevice, PCI_QXL) #define QXL_DEFAULT_REVISION (QXL_REVISION_STABLE_V12 + 1) /* qxl.c */ -void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); +/** + * qxl_phys2virt: Get a pointer within a PCI VRAM memory region. + * + * @qxl: QXL device + * @phys: physical offset of buffer within the VRAM + * @group_id: memory slot group + * @size: size of the buffer + * + * Returns a host pointer to a buffer placed at offset @phys within the + * active slot @group_id of the PCI VGA RAM memory region associated with + * the @qxl device. If the slot is inactive, or the offset + size are out + * of the memory region, returns NULL. + * + * Use with care; by the time this function returns, the returned pointer is + * not protected by RCU anymore. If the caller is not within an RCU critical + * section and does not hold the iothread lock, it must have other means of + * protecting the pointer, such as a reference to the region that includes + * the incoming ram_addr_t. + * + */ +void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id, + size_t size); void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) G_GNUC_PRINTF(2, 3); diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 492b2421ab..7a34bc0998 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -941,7 +941,7 @@ static void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) gic_update(s); } -static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) +static uint8_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) { GICState *s = (GICState *)opaque; uint32_t res; @@ -955,6 +955,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) cm = 1 << cpu; if (offset < 0x100) { if (offset == 0) { /* GICD_CTLR */ + /* We rely here on the only non-zero bits being in byte 0 */ if (s->security_extn && !attrs.secure) { /* The NS bank of this register is just an alias of the * EnableGrp1 bit in the S bank version. @@ -964,13 +965,26 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) return s->ctlr; } } - if (offset == 4) - /* Interrupt Controller Type Register */ - return ((s->num_irq / 32) - 1) - | ((s->num_cpu - 1) << 5) - | (s->security_extn << 10); - if (offset < 0x08) + if (offset == 4) { + /* GICD_TYPER byte 0 */ + return ((s->num_irq / 32) - 1) | ((s->num_cpu - 1) << 5); + } + if (offset == 5) { + /* GICD_TYPER byte 1 */ + return (s->security_extn << 2); + } + if (offset == 8) { + /* GICD_IIDR byte 0 */ + return 0x3b; /* Arm JEP106 identity */ + } + if (offset == 9) { + /* GICD_IIDR byte 1 */ + return 0x04; /* Arm JEP106 identity */ + } + if (offset < 0x0c) { + /* All other bytes in this range are RAZ */ return 0; + } if (offset >= 0x80) { /* Interrupt Group Registers: these RAZ/WI if this is an NS * access to a GIC with the security extensions, or if the GIC diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c index 68dfb9f88a..7d5f5a757d 100644 --- a/hw/loongarch/acpi-build.c +++ b/hw/loongarch/acpi-build.c @@ -226,7 +226,8 @@ static void build_uart_device_aml(Aml *table) aml_append(crs, aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, AML_NON_CACHEABLE, AML_READ_WRITE, - 0, 0x1FE001E0, 0x1FE001E7, 0, 0x8)); + 0, VIRT_UART_BASE, VIRT_UART_BASE + VIRT_UART_SIZE - 1, + 0, VIRT_UART_SIZE)); aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, AML_SHARED, &uart_irq, 1)); aml_append(dev, aml_name_decl("_CRS", crs)); diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 5136940b0b..958be74fa1 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -53,7 +53,7 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams) nodename = g_strdup_printf("/rtc@%" PRIx64, base); qemu_fdt_add_subnode(ms->fdt, nodename); qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "loongson,ls7a-rtc"); - qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 0x0, base, size); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size); g_free(nodename); } @@ -69,6 +69,7 @@ static void fdt_add_uart_node(LoongArchMachineState *lams) qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a"); qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size); qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000); + qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); g_free(nodename); } @@ -87,6 +88,7 @@ static void create_fdt(LoongArchMachineState *lams) "linux,dummy-loongson3"); qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); + qemu_fdt_add_subnode(ms->fdt, "/chosen"); } static void fdt_add_cpu_nodes(const LoongArchMachineState *lams) diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index e6643e3c9d..700b1b66b6 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -77,7 +77,6 @@ ( ( input ) & ( size - 1 ) ) #define ETHER_TYPE_LEN 2 -#define ETH_MTU 1500 #define VLAN_TCI_LEN 2 #define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN) @@ -1934,8 +1933,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) #define CP_TX_LS (1<<28) /* large send packet flag */ #define CP_TX_LGSEN (1<<27) -/* large send MSS mask, bits 16...25 */ -#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1) +/* large send MSS mask, bits 16...26 */ +#define CP_TC_LGSEN_MSS_SHIFT 16 +#define CP_TC_LGSEN_MSS_MASK ((1 << 11) - 1) /* IP checksum offload flag */ #define CP_TX_IPCS (1<<18) @@ -2027,18 +2027,21 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) s->currCPlusTxDesc = 0; } + /* Build the Tx Status Descriptor */ + uint32_t tx_status = txdw0; + /* transfer ownership to target */ - txdw0 &= ~CP_TX_OWN; + tx_status &= ~CP_TX_OWN; /* reset error indicator bits */ - txdw0 &= ~CP_TX_STATUS_UNF; - txdw0 &= ~CP_TX_STATUS_TES; - txdw0 &= ~CP_TX_STATUS_OWC; - txdw0 &= ~CP_TX_STATUS_LNKF; - txdw0 &= ~CP_TX_STATUS_EXC; + tx_status &= ~CP_TX_STATUS_UNF; + tx_status &= ~CP_TX_STATUS_TES; + tx_status &= ~CP_TX_STATUS_OWC; + tx_status &= ~CP_TX_STATUS_LNKF; + tx_status &= ~CP_TX_STATUS_EXC; /* update ring data */ - val = cpu_to_le32(txdw0); + val = cpu_to_le32(tx_status); pci_dma_write(d, cplus_tx_ring_desc, (uint8_t *)&val, 4); /* Now decide if descriptor being processed is holding the last segment of packet */ @@ -2132,7 +2135,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) } ip_data_len -= hlen; - if (txdw0 & CP_TX_IPCS) + if (!(txdw0 & CP_TX_LGSEN) && (txdw0 & CP_TX_IPCS)) { DPRINTF("+++ C+ mode need IP checksum\n"); @@ -2149,10 +2152,11 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) goto skip_offload; } - int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; + int large_send_mss = (txdw0 >> CP_TC_LGSEN_MSS_SHIFT) & + CP_TC_LGSEN_MSS_MASK; - DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " - "frame data %d specified MSS=%d\n", ETH_MTU, + DPRINTF("+++ C+ mode offloaded task TSO IP data %d " + "frame data %d specified MSS=%d\n", ip_data_len, saved_size - ETH_HLEN, large_send_mss); int tcp_send_offset = 0; @@ -2177,25 +2181,22 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) goto skip_offload; } - /* ETH_MTU = ip header len + tcp header len + payload */ int tcp_data_len = ip_data_len - tcp_hlen; - int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP " - "data len %d TCP chunk size %d\n", ip_data_len, - tcp_hlen, tcp_data_len, tcp_chunk_size); + "data len %d\n", ip_data_len, tcp_hlen, tcp_data_len); /* note the cycle below overwrites IP header data, but restores it from saved_ip_header before sending packet */ int is_last_frame = 0; - for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) + for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += large_send_mss) { - uint16_t chunk_size = tcp_chunk_size; + uint16_t chunk_size = large_send_mss; /* check if this is the last frame */ - if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) + if (tcp_send_offset + large_send_mss >= tcp_data_len) { is_last_frame = 1; chunk_size = tcp_data_len - tcp_send_offset; @@ -2244,7 +2245,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); /* increment IP id for subsequent frames */ - ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); + ip->ip_id = cpu_to_be16(tcp_send_offset/large_send_mss + be16_to_cpu(ip->ip_id)); ip->ip_sum = 0; ip->ip_sum = ip_checksum(eth_payload_data, hlen); @@ -2265,7 +2266,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* Stop sending this frame */ saved_size = 0; } - else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + else if (!(txdw0 & CP_TX_LGSEN) && (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))) { DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index dfc6dfd89c..7fc86e7905 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -140,7 +140,7 @@ void s390_ipl_clear_reset_request(void); * have an offset of 4 + n * 8 bytes within the struct in order * to keep it double-word aligned. * The total size of the struct must never exceed 28 bytes. - * This definition must be kept in sync with the defininition + * This definition must be kept in sync with the definition * in pc-bios/s390-ccw/iplb.h. */ struct QemuIplParameters { diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c index 2aefa508a0..5f0adb0b4a 100644 --- a/hw/s390x/s390-pci-vfio.c +++ b/hw/s390x/s390-pci-vfio.c @@ -313,7 +313,7 @@ retry: /* * Get the host function handle from the vfio CLP capabilities chain. Returns * true if a fh value was placed into the provided buffer. Returns false - * if a fh could not be obtained (ioctl failed or capabilitiy version does + * if a fh could not be obtained (ioctl failed or capability version does * not include the fh) */ bool s390_pci_get_host_fh(S390PCIBusDevice *pbdev, uint32_t *fh) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 7d80bc1837..2e64ffab45 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -354,7 +354,7 @@ static int s390_machine_protect(S390CcwMachineState *ms) } error_setg(&pv_mig_blocker, - "protected VMs are currently not migrateable."); + "protected VMs are currently not migratable."); rc = migrate_add_blocker(pv_mig_blocker, &local_err); if (rc) { ram_block_discard_disable(false); @@ -449,7 +449,7 @@ static void s390_machine_reset(MachineState *machine, ShutdownCause reason) break; case S390_RESET_MODIFIED_CLEAR: /* - * Susbsystem reset needs to be done before we unshare memory + * Subsystem reset needs to be done before we unshare memory * and lose access to VIRTIO structures in guest memory. */ subsystem_reset(); @@ -462,7 +462,7 @@ static void s390_machine_reset(MachineState *machine, ShutdownCause reason) break; case S390_RESET_LOAD_NORMAL: /* - * Susbsystem reset needs to be done before we unshare memory + * Subsystem reset needs to be done before we unshare memory * and lose access to VIRTIO structures in guest memory. */ subsystem_reset(); diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c index 455d6eabf6..51e5e90830 100644 --- a/hw/sd/allwinner-sdhost.c +++ b/hw/sd/allwinner-sdhost.c @@ -65,7 +65,7 @@ enum { REG_SD_DLBA = 0x84, /* Descriptor List Base Address */ REG_SD_IDST = 0x88, /* Internal DMA Controller Status */ REG_SD_IDIE = 0x8C, /* Internal DMA Controller IRQ Enable */ - REG_SD_THLDC = 0x100, /* Card Threshold Control */ + REG_SD_THLDC = 0x100, /* Card Threshold Control / FIFO (sun4i only)*/ REG_SD_DSBD = 0x10C, /* eMMC DDR Start Bit Detection Control */ REG_SD_RES_CRC = 0x110, /* Response CRC from card/eMMC */ REG_SD_DATA7_CRC = 0x114, /* CRC Data 7 from card/eMMC */ @@ -415,10 +415,29 @@ static void allwinner_sdhost_dma(AwSdHostState *s) } } +static uint32_t allwinner_sdhost_fifo_read(AwSdHostState *s) +{ + uint32_t res = 0; + + if (sdbus_data_ready(&s->sdbus)) { + sdbus_read_data(&s->sdbus, &res, sizeof(uint32_t)); + le32_to_cpus(&res); + allwinner_sdhost_update_transfer_cnt(s, sizeof(uint32_t)); + allwinner_sdhost_auto_stop(s); + allwinner_sdhost_update_irq(s); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: no data ready on SD bus\n", + __func__); + } + + return res; +} + static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, unsigned size) { AwSdHostState *s = AW_SDHOST(opaque); + AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s); uint32_t res = 0; switch (offset) { @@ -508,8 +527,12 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, case REG_SD_IDIE: /* Internal DMA Controller Interrupt Enable */ res = s->dmac_irq; break; - case REG_SD_THLDC: /* Card Threshold Control */ - res = s->card_threshold; + case REG_SD_THLDC: /* Card Threshold Control or FIFO register (sun4i) */ + if (sc->is_sun4i) { + res = allwinner_sdhost_fifo_read(s); + } else { + res = s->card_threshold; + } break; case REG_SD_DSBD: /* eMMC DDR Start Bit Detection Control */ res = s->startbit_detect; @@ -531,16 +554,7 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, res = s->status_crc; break; case REG_SD_FIFO: /* Read/Write FIFO */ - if (sdbus_data_ready(&s->sdbus)) { - sdbus_read_data(&s->sdbus, &res, sizeof(uint32_t)); - le32_to_cpus(&res); - allwinner_sdhost_update_transfer_cnt(s, sizeof(uint32_t)); - allwinner_sdhost_auto_stop(s); - allwinner_sdhost_update_irq(s); - } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s: no data ready on SD bus\n", - __func__); - } + res = allwinner_sdhost_fifo_read(s); break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %" @@ -553,11 +567,20 @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, return res; } +static void allwinner_sdhost_fifo_write(AwSdHostState *s, uint64_t value) +{ + uint32_t u32 = cpu_to_le32(value); + sdbus_write_data(&s->sdbus, &u32, sizeof(u32)); + allwinner_sdhost_update_transfer_cnt(s, sizeof(u32)); + allwinner_sdhost_auto_stop(s); + allwinner_sdhost_update_irq(s); +} + static void allwinner_sdhost_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { AwSdHostState *s = AW_SDHOST(opaque); - uint32_t u32; + AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s); trace_allwinner_sdhost_write(offset, value, size); @@ -657,18 +680,18 @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset, s->dmac_irq = value; allwinner_sdhost_update_irq(s); break; - case REG_SD_THLDC: /* Card Threshold Control */ - s->card_threshold = value; + case REG_SD_THLDC: /* Card Threshold Control or FIFO (sun4i) */ + if (sc->is_sun4i) { + allwinner_sdhost_fifo_write(s, value); + } else { + s->card_threshold = value; + } break; case REG_SD_DSBD: /* eMMC DDR Start Bit Detection Control */ s->startbit_detect = value; break; case REG_SD_FIFO: /* Read/Write FIFO */ - u32 = cpu_to_le32(value); - sdbus_write_data(&s->sdbus, &u32, sizeof(u32)); - allwinner_sdhost_update_transfer_cnt(s, sizeof(u32)); - allwinner_sdhost_auto_stop(s); - allwinner_sdhost_update_irq(s); + allwinner_sdhost_fifo_write(s, value); break; case REG_SD_RES_CRC: /* Response CRC from card/eMMC */ case REG_SD_DATA7_CRC: /* CRC Data 7 from card/eMMC */ @@ -834,12 +857,14 @@ static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data) { AwSdHostClass *sc = AW_SDHOST_CLASS(klass); sc->max_desc_size = 8 * KiB; + sc->is_sun4i = true; } static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data) { AwSdHostClass *sc = AW_SDHOST_CLASS(klass); sc->max_desc_size = 64 * KiB; + sc->is_sun4i = false; } static const TypeInfo allwinner_sdhost_info = { diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c index e934b1a5b1..643d4643e4 100644 --- a/hw/usb/hcd-xhci-pci.c +++ b/hw/usb/hcd-xhci-pci.c @@ -85,7 +85,7 @@ static void xhci_pci_reset(DeviceState *dev) { XHCIPciState *s = XHCI_PCI(dev); - device_legacy_reset(DEVICE(&s->xhci)); + device_cold_reset(DEVICE(&s->xhci)); } static int xhci_pci_vmstate_post_load(void *opaque, int version_id) diff --git a/hw/usb/hcd-xhci-sysbus.c b/hw/usb/hcd-xhci-sysbus.c index a14e438196..faf57b4797 100644 --- a/hw/usb/hcd-xhci-sysbus.c +++ b/hw/usb/hcd-xhci-sysbus.c @@ -29,7 +29,7 @@ void xhci_sysbus_reset(DeviceState *dev) { XHCISysbusState *s = XHCI_SYSBUS(dev); - device_legacy_reset(DEVICE(&s->xhci)); + device_cold_reset(DEVICE(&s->xhci)); } static void xhci_sysbus_realize(DeviceState *dev, Error **errp) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 8299f35e66..b89b618ec2 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -796,7 +796,7 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) */ } while (length < TRB_LINK_LIMIT * 65536 / TRB_SIZE); - qemu_log_mask(LOG_GUEST_ERROR, "%s: exceeded maximum tranfer ring size!\n", + qemu_log_mask(LOG_GUEST_ERROR, "%s: exceeded maximum transfer ring size!\n", __func__); return -1; diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 1bd30efc3e..fd7df599bc 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1280,8 +1280,7 @@ static void usbredir_create_parser(USBRedirDevice *dev) } #endif - if (runstate_check(RUN_STATE_INMIGRATE) || - runstate_check(RUN_STATE_PRELAUNCH)) { + if (runstate_check(RUN_STATE_INMIGRATE)) { flags |= usbredirparser_fl_no_hello; } usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 1500680458..f4fb6a2111 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -42,7 +42,8 @@ static inline long clear_bmap_size(uint64_t pages, uint8_t shift) } /** - * clear_bmap_set: set clear bitmap for the page range + * clear_bmap_set: set clear bitmap for the page range. Must be with + * bitmap_mutex held. * * @rb: the ramblock to operate on * @start: the start page number @@ -55,12 +56,12 @@ static inline void clear_bmap_set(RAMBlock *rb, uint64_t start, { uint8_t shift = rb->clear_bmap_shift; - bitmap_set_atomic(rb->clear_bmap, start >> shift, - clear_bmap_size(npages, shift)); + bitmap_set(rb->clear_bmap, start >> shift, clear_bmap_size(npages, shift)); } /** - * clear_bmap_test_and_clear: test clear bitmap for the page, clear if set + * clear_bmap_test_and_clear: test clear bitmap for the page, clear if set. + * Must be with bitmap_mutex held. * * @rb: the ramblock to operate on * @page: the page number to check @@ -71,7 +72,7 @@ static inline bool clear_bmap_test_and_clear(RAMBlock *rb, uint64_t page) { uint8_t shift = rb->clear_bmap_shift; - return bitmap_test_and_clear_atomic(rb->clear_bmap, page >> shift, 1); + return bitmap_test_and_clear(rb->clear_bmap, page >> shift, 1); } static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset) diff --git a/include/exec/ramblock.h b/include/exec/ramblock.h index 6cbedf9e0c..adc03df59c 100644 --- a/include/exec/ramblock.h +++ b/include/exec/ramblock.h @@ -53,6 +53,9 @@ struct RAMBlock { * and split clearing of dirty bitmap on the remote node (e.g., * KVM). The bitmap will be set only when doing global sync. * + * It is only used during src side of ram migration, and it is + * protected by the global ram_state.bitmap_mutex. + * * NOTE: this bitmap is different comparing to the other bitmaps * in that one bit can represent multiple guest pages (which is * decided by the `clear_bmap_shift' variable below). On diff --git a/include/hw/sd/allwinner-sdhost.h b/include/hw/sd/allwinner-sdhost.h index bfe08ff4ef..30c1e60404 100644 --- a/include/hw/sd/allwinner-sdhost.h +++ b/include/hw/sd/allwinner-sdhost.h @@ -130,6 +130,7 @@ struct AwSdHostClass { /** Maximum buffer size in bytes per DMA descriptor */ size_t max_desc_size; + bool is_sun4i; }; diff --git a/include/net/net.h b/include/net/net.h index 3db75ff841..dc20b31e9f 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -177,7 +177,8 @@ ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf, void qemu_purge_queued_packets(NetClientState *nc); void qemu_flush_queued_packets(NetClientState *nc); void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge); -void qemu_set_info_str(NetClientState *nc, const char *fmt, ...); +void qemu_set_info_str(NetClientState *nc, + const char *fmt, ...) G_GNUC_PRINTF(2, 3); void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]); bool qemu_has_ufo(NetClientState *nc); bool qemu_has_vnet_hdr(NetClientState *nc); diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index 82a1d2f41f..3ccb00865f 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -253,6 +253,7 @@ void bitmap_set(unsigned long *map, long i, long len); void bitmap_set_atomic(unsigned long *map, long i, long len); void bitmap_clear(unsigned long *map, long start, long nr); bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr); +bool bitmap_test_and_clear(unsigned long *map, long start, long nr); void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src, long nr); unsigned long bitmap_find_next_zero_area(unsigned long *map, diff --git a/meson.build b/meson.build index cf3e517e56..5c6b5a1c75 100644 --- a/meson.build +++ b/meson.build @@ -1246,6 +1246,8 @@ endif gtk = not_found gtkx11 = not_found vte = not_found +have_gtk_clipboard = get_option('gtk_clipboard').enabled() + if not get_option('gtk').auto() or have_system gtk = dependency('gtk+-3.0', version: '>=3.22.0', method: 'pkg-config', @@ -1264,6 +1266,8 @@ if not get_option('gtk').auto() or have_system required: get_option('vte'), kwargs: static_kwargs) endif + elif have_gtk_clipboard + error('GTK clipboard requested, but GTK not found') endif endif @@ -1842,6 +1846,7 @@ if glusterfs.found() endif config_host_data.set('CONFIG_GTK', gtk.found()) config_host_data.set('CONFIG_VTE', vte.found()) +config_host_data.set('CONFIG_GTK_CLIPBOARD', have_gtk_clipboard) config_host_data.set('CONFIG_LIBATTR', have_old_libattr) config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found()) config_host_data.set('CONFIG_EBPF', libbpf.found()) diff --git a/meson_options.txt b/meson_options.txt index 66128178bf..4b749ca549 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -219,6 +219,13 @@ option('vnc_sasl', type : 'feature', value : 'auto', description: 'SASL authentication for VNC server') option('vte', type : 'feature', value : 'auto', description: 'vte support for the gtk UI') + +# GTK Clipboard implementation is disabled by default, since it may cause hangs +# of the guest VCPUs. See gitlab issue 1150: +# https://gitlab.com/qemu-project/qemu/-/issues/1150 + +option('gtk_clipboard', type: 'feature', value : 'disabled', + description: 'clipboard support for the gtk UI (EXPERIMENTAL, MAY HANG)') option('xkbcommon', type : 'feature', value : 'auto', description: 'xkbcommon support') option('zstd', type : 'feature', value : 'auto', diff --git a/migration/block.c b/migration/block.c index 3577c815a9..4347da1526 100644 --- a/migration/block.c +++ b/migration/block.c @@ -880,8 +880,8 @@ static void block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, blk_mig_unlock(); /* Report at least one block pending during bulk phase */ - if (pending <= max_size && !block_mig_state.bulk_completed) { - pending = max_size + BLK_MIG_BLOCK_SIZE; + if (!pending && !block_mig_state.bulk_completed) { + pending = BLK_MIG_BLOCK_SIZE; } trace_migration_block_save_pending(pending); diff --git a/migration/channel-block.c b/migration/channel-block.c index c55c8c93ce..f4ab53acdb 100644 --- a/migration/channel-block.c +++ b/migration/channel-block.c @@ -62,7 +62,8 @@ qio_channel_block_readv(QIOChannel *ioc, qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov); ret = bdrv_readv_vmstate(bioc->bs, &qiov, bioc->offset); if (ret < 0) { - return ret; + error_setg_errno(errp, -ret, "bdrv_readv_vmstate failed"); + return -1; } bioc->offset += qiov.size; @@ -86,7 +87,8 @@ qio_channel_block_writev(QIOChannel *ioc, qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov); ret = bdrv_writev_vmstate(bioc->bs, &qiov, bioc->offset); if (ret < 0) { - return ret; + error_setg_errno(errp, -ret, "bdrv_writev_vmstate failed"); + return -1; } bioc->offset += qiov.size; diff --git a/migration/migration.c b/migration/migration.c index 739bb683f3..f485eea5fb 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1337,6 +1337,24 @@ static bool migrate_caps_check(bool *cap_list, error_setg(errp, "Postcopy preempt requires postcopy-ram"); return false; } + + /* + * Preempt mode requires urgent pages to be sent in separate + * channel, OTOH compression logic will disorder all pages into + * different compression channels, which is not compatible with the + * preempt assumptions on channel assignments. + */ + if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) { + error_setg(errp, "Postcopy preempt not compatible with compress"); + return false; + } + } + + if (cap_list[MIGRATION_CAPABILITY_MULTIFD]) { + if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) { + error_setg(errp, "Multifd is not compatible with compress"); + return false; + } } return true; diff --git a/migration/multifd.c b/migration/multifd.c index 586ddc9d65..509bbbe3bf 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -566,6 +566,23 @@ void multifd_save_cleanup(void) multifd_send_state = NULL; } +static int multifd_zero_copy_flush(QIOChannel *c) +{ + int ret; + Error *err = NULL; + + ret = qio_channel_flush(c, &err); + if (ret < 0) { + error_report_err(err); + return -1; + } + if (ret == 1) { + dirty_sync_missed_zero_copy(); + } + + return ret; +} + int multifd_send_sync_main(QEMUFile *f) { int i; @@ -616,17 +633,8 @@ int multifd_send_sync_main(QEMUFile *f) qemu_mutex_unlock(&p->mutex); qemu_sem_post(&p->sem); - if (flush_zero_copy && p->c) { - int ret; - Error *err = NULL; - - ret = qio_channel_flush(p->c, &err); - if (ret < 0) { - error_report_err(err); - return -1; - } else if (ret == 1) { - dirty_sync_missed_zero_copy(); - } + if (flush_zero_copy && p->c && (multifd_zero_copy_flush(p->c) < 0)) { + return -1; } } for (i = 0; i < migrate_multifd_channels(); i++) { diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 4f400c2e52..2d5f74ffc2 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -79,6 +79,30 @@ int qemu_file_shutdown(QEMUFile *f) int ret = 0; f->shutdown = true; + + /* + * We must set qemufile error before the real shutdown(), otherwise + * there can be a race window where we thought IO all went though + * (because last_error==NULL) but actually IO has already stopped. + * + * If without correct ordering, the race can happen like this: + * + * page receiver other thread + * ------------- ------------ + * qemu_get_buffer() + * do shutdown() + * returns 0 (buffer all zero) + * (we didn't check this retcode) + * try to detect IO error + * last_error==NULL, IO okay + * install ALL-ZERO page + * set last_error + * --> guest crash! + */ + if (!f->last_error) { + qemu_file_set_error(f, -EIO); + } + if (!qio_channel_has_feature(f->ioc, QIO_CHANNEL_FEATURE_SHUTDOWN)) { return -ENOSYS; @@ -88,9 +112,6 @@ int qemu_file_shutdown(QEMUFile *f) ret = -EIO; } - if (!f->last_error) { - qemu_file_set_error(f, -EIO); - } return ret; } diff --git a/migration/ram.c b/migration/ram.c index dc1de9ddbc..1338e47665 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2305,13 +2305,12 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss) } /* - * Do not use multifd for: - * 1. Compression as the first page in the new block should be posted out - * before sending the compressed page - * 2. In postcopy as one whole host page should be placed + * Do not use multifd in postcopy as one whole host page should be + * placed. Meanwhile postcopy requires atomic update of pages, so even + * if host page size == guest page size the dest guest during run may + * still see partially copied pages which is data corruption. */ - if (!save_page_use_compression(rs) && migrate_use_multifd() - && !migration_in_postcopy()) { + if (migrate_use_multifd() && !migration_in_postcopy()) { return ram_save_multifd_page(rs, block, offset); } @@ -2546,14 +2545,22 @@ static int ram_find_and_save_block(RAMState *rs) return pages; } + /* + * Always keep last_seen_block/last_page valid during this procedure, + * because find_dirty_block() relies on these values (e.g., we compare + * last_seen_block with pss.block to see whether we searched all the + * ramblocks) to detect the completion of migration. Having NULL value + * of last_seen_block can conditionally cause below loop to run forever. + */ + if (!rs->last_seen_block) { + rs->last_seen_block = QLIST_FIRST_RCU(&ram_list.blocks); + rs->last_page = 0; + } + pss.block = rs->last_seen_block; pss.page = rs->last_page; pss.complete_round = false; - if (!pss.block) { - pss.block = QLIST_FIRST_RCU(&ram_list.blocks); - } - do { again = true; found = get_queued_page(rs, &pss); diff --git a/net/socket.c b/net/socket.c index 4944bb70d5..e62137c839 100644 --- a/net/socket.c +++ b/net/socket.c @@ -179,7 +179,7 @@ static void net_socket_send(void *opaque) s->fd = -1; net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); s->nc.link_down = true; - qemu_set_info_str(&s->nc, ""); + qemu_set_info_str(&s->nc, "%s", ""); return; } diff --git a/net/stream.c b/net/stream.c index 53b7040cc4..37ff727e0c 100644 --- a/net/stream.c +++ b/net/stream.c @@ -167,7 +167,7 @@ static gboolean net_stream_send(QIOChannel *ioc, net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); s->nc.link_down = true; - qemu_set_info_str(&s->nc, ""); + qemu_set_info_str(&s->nc, "%s", ""); qapi_event_send_netdev_stream_disconnected(s->nc.name); @@ -245,7 +245,7 @@ static void net_stream_listen(QIONetListener *listener, } g_assert(addr != NULL); uri = socket_uri(addr); - qemu_set_info_str(&s->nc, uri); + qemu_set_info_str(&s->nc, "%s", uri); g_free(uri); qapi_event_send_netdev_stream_connected(s->nc.name, addr); qapi_free_SocketAddress(addr); @@ -319,7 +319,7 @@ static void net_stream_client_connected(QIOTask *task, gpointer opaque) addr = qio_channel_socket_get_remote_address(sioc, NULL); g_assert(addr != NULL); uri = socket_uri(addr); - qemu_set_info_str(&s->nc, uri); + qemu_set_info_str(&s->nc, "%s", uri); g_free(uri); ret = qemu_socket_try_set_nonblock(sioc->fd); diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin Binary files differindex 6163fb8149..211b2a4da2 100644 --- a/pc-bios/bios-256k.bin +++ b/pc-bios/bios-256k.bin diff --git a/pc-bios/bios-microvm.bin b/pc-bios/bios-microvm.bin Binary files differindex 97fbd3192a..6204a714cd 100644 --- a/pc-bios/bios-microvm.bin +++ b/pc-bios/bios-microvm.bin diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin Binary files differindex 68f65ff2fd..12d6a037be 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h index 1e5d4e92e1..88a88adfd2 100644 --- a/pc-bios/s390-ccw/cio.h +++ b/pc-bios/s390-ccw/cio.h @@ -20,7 +20,7 @@ struct pmcw { __u32 intparm; /* interruption parameter */ __u32 qf:1; /* qdio facility */ __u32 w:1; - __u32 isc:3; /* interruption sublass */ + __u32 isc:3; /* interruption subclass */ __u32 res5:3; /* reserved zeros */ __u32 ena:1; /* enabled */ __u32 lm:2; /* limit mode */ diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h index 772d5c57c9..cb6ac8a880 100644 --- a/pc-bios/s390-ccw/iplb.h +++ b/pc-bios/s390-ccw/iplb.h @@ -81,7 +81,7 @@ extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE))); #define QIPL_FLAG_BM_OPTS_ZIPL 0x40 /* - * This definition must be kept in sync with the defininition + * This definition must be kept in sync with the definition * in hw/s390x/ipl.h */ struct QemuIplParameters { diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S index 4d5ad21653..6072906df4 100644 --- a/pc-bios/s390-ccw/start.S +++ b/pc-bios/s390-ccw/start.S @@ -19,7 +19,7 @@ _start: larl %r2, __bss_start larl %r3, _end slgr %r3, %r2 /* get sizeof bss */ - ltgr %r3,%r3 /* bss emtpy? */ + ltgr %r3,%r3 /* bss empty? */ jz done aghi %r3,-1 srlg %r4,%r3,8 /* how many 256 byte chunks? */ diff --git a/pc-bios/vgabios-ati.bin b/pc-bios/vgabios-ati.bin Binary files differindex 4533d0d063..39b2405148 100644 --- a/pc-bios/vgabios-ati.bin +++ b/pc-bios/vgabios-ati.bin diff --git a/pc-bios/vgabios-bochs-display.bin b/pc-bios/vgabios-bochs-display.bin Binary files differindex 3ecf92de01..b20d67ccf5 100644 --- a/pc-bios/vgabios-bochs-display.bin +++ b/pc-bios/vgabios-bochs-display.bin diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin Binary files differindex 9b4ffdf45f..ebe53366e4 100644 --- a/pc-bios/vgabios-cirrus.bin +++ b/pc-bios/vgabios-cirrus.bin diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin Binary files differindex 8a27dac557..4b5573a857 100644 --- a/pc-bios/vgabios-qxl.bin +++ b/pc-bios/vgabios-qxl.bin diff --git a/pc-bios/vgabios-ramfb.bin b/pc-bios/vgabios-ramfb.bin Binary files differindex ec9541cfb4..d458ec7436 100644 --- a/pc-bios/vgabios-ramfb.bin +++ b/pc-bios/vgabios-ramfb.bin diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin Binary files differindex 55390c45c9..797e1036c9 100644 --- a/pc-bios/vgabios-stdvga.bin +++ b/pc-bios/vgabios-stdvga.bin diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin Binary files differindex 2334733a75..3f8fe9de13 100644 --- a/pc-bios/vgabios-virtio.bin +++ b/pc-bios/vgabios-virtio.bin diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin Binary files differindex b668ac04a6..d5f263a9f7 100644 --- a/pc-bios/vgabios-vmware.bin +++ b/pc-bios/vgabios-vmware.bin diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin Binary files differindex a924891ea5..d26af416ce 100644 --- a/pc-bios/vgabios.bin +++ b/pc-bios/vgabios.bin diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 89e377be90..b6836354ac 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -136,7 +136,7 @@ bool replay_next_event_is(int event); /*! Reads next clock value from the file. If clock kind read from the file is different from the parameter, the value is not used. */ -void replay_read_next_clock(unsigned int kind); +void replay_read_next_clock(ReplayClockKind kind); /* Asynchronous events queue */ diff --git a/roms/seabios b/roms/seabios -Subproject d239552ce7220e448ae81f41515138f7b9e3c4d +Subproject 3208b098f51a9ef96d0dfa71d5ec3a3eaec88f0 diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 2cb0de5601..aa6e30ea91 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -93,6 +93,7 @@ meson_options_help() { printf "%s\n" ' glusterfs Glusterfs block device driver' printf "%s\n" ' gnutls GNUTLS cryptography support' printf "%s\n" ' gtk GTK+ user interface' + printf "%s\n" ' gtk-clipboard clipboard support for GTK (EXPERIMENTAL, MAY HANG)' printf "%s\n" ' guest-agent Build QEMU Guest Agent' printf "%s\n" ' guest-agent-msi Build MSI package for the QEMU Guest Agent' printf "%s\n" ' hax HAX acceleration support' @@ -274,6 +275,8 @@ _meson_option_parse() { --disable-gprof) printf "%s" -Dgprof=false ;; --enable-gtk) printf "%s" -Dgtk=enabled ;; --disable-gtk) printf "%s" -Dgtk=disabled ;; + --enable-gtk-clipboard) printf "%s" -Dgtk_clipboard=enabled ;; + --disable-gtk-clipboard) printf "%s" -Dgtk_clipboard=disabled ;; --enable-guest-agent) printf "%s" -Dguest_agent=enabled ;; --disable-guest-agent) printf "%s" -Dguest_agent=disabled ;; --enable-guest-agent-msi) printf "%s" -Dguest_agent_msi=enabled ;; diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index ffed4729a3..d6ee6e7d91 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -45,6 +45,17 @@ #include "libvhost-user.h" /* usually provided by GLib */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#if !defined(__clang__) && (__GNUC__ == 4 && __GNUC_MINOR__ == 4) +#define G_GNUC_PRINTF(format_idx, arg_idx) \ + __attribute__((__format__(gnu_printf, format_idx, arg_idx))) +#else +#define G_GNUC_PRINTF(format_idx, arg_idx) \ + __attribute__((__format__(__printf__, format_idx, arg_idx))) +#endif +#else /* !__GNUC__ */ +#define G_GNUC_PRINTF(format_idx, arg_idx) +#endif /* !__GNUC__ */ #ifndef MIN #define MIN(x, y) ({ \ typeof(x) _min1 = (x); \ @@ -151,7 +162,7 @@ vu_request_to_string(unsigned int req) } } -static void +static void G_GNUC_PRINTF(2, 3) vu_panic(VuDev *dev, const char *msg, ...) { char *buf = NULL; @@ -651,7 +662,8 @@ generate_faults(VuDev *dev) { if (ioctl(dev->postcopy_ufd, UFFDIO_REGISTER, ®_struct)) { vu_panic(dev, "%s: Failed to userfault region %d " - "@%p + size:%zx offset: %zx: (ufd=%d)%s\n", + "@%" PRIx64 " + size:%" PRIx64 " offset: %" PRIx64 + ": (ufd=%d)%s\n", __func__, i, dev_region->mmap_addr, dev_region->size, dev_region->mmap_offset, @@ -700,7 +712,7 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { if (vmsg->size < VHOST_USER_MEM_REG_SIZE) { close(vmsg->fds[0]); vu_panic(dev, "VHOST_USER_ADD_MEM_REG requires a message size of at " - "least %d bytes and only %d bytes were received", + "least %zu bytes and only %d bytes were received", VHOST_USER_MEM_REG_SIZE, vmsg->size); return false; } @@ -826,7 +838,7 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { if (vmsg->size < VHOST_USER_MEM_REG_SIZE) { vmsg_close_fds(vmsg); vu_panic(dev, "VHOST_USER_REM_MEM_REG requires a message size of at " - "least %d bytes and only %d bytes were received", + "least %zu bytes and only %d bytes were received", VHOST_USER_MEM_REG_SIZE, vmsg->size); return false; } diff --git a/target/arm/cpu.c b/target/arm/cpu.c index a021df9e9e..38d066c294 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -91,9 +91,9 @@ void arm_cpu_synchronize_from_tb(CPUState *cs, } } -static void arm_restore_state_to_opc(CPUState *cs, - const TranslationBlock *tb, - const uint64_t *data) +void arm_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data) { CPUARMState *env = cs->env_ptr; diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 60ff539fa1..9a2cef7d05 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -1035,6 +1035,7 @@ static const struct TCGCPUOps arm_v7m_tcg_ops = { .initialize = arm_translate_init, .synchronize_from_tb = arm_cpu_synchronize_from_tb, .debug_excp_handler = arm_debug_excp_handler, + .restore_state_to_opc = arm_restore_state_to_opc, #ifdef CONFIG_USER_ONLY .record_sigsegv = arm_cpu_record_sigsegv, diff --git a/target/arm/internals.h b/target/arm/internals.h index d9121d9ff8..161e42d50f 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -185,6 +185,10 @@ static inline int r14_bank_number(int mode) void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu); void arm_translate_init(void); +void arm_restore_state_to_opc(CPUState *cs, + const TranslationBlock *tb, + const uint64_t *data); + #ifdef CONFIG_TCG void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); #endif /* CONFIG_TCG */ diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 3745ac9723..f812734bfb 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -1172,7 +1172,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, ARMCPU *cpu = env_archcpu(env); ARMMMUIdx mmu_idx = ptw->in_mmu_idx; bool is_secure = ptw->in_secure; - uint32_t level; + int32_t level; ARMVAParameters param; uint64_t ttbr; hwaddr descaddr, indexmask, indexmask_grainsize; @@ -1222,6 +1222,14 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, ps = MIN(ps, param.ps); assert(ps < ARRAY_SIZE(pamax_map)); outputsize = pamax_map[ps]; + + /* + * With LPA2, the effective output address (OA) size is at most 48 bits + * unless TCR.DS == 1 + */ + if (!param.ds && param.gran != Gran64K) { + outputsize = MIN(outputsize, 48); + } } else { param = aa32_va_parameters(env, address, mmu_idx); level = 1; @@ -1294,7 +1302,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, */ uint32_t sl0 = extract32(tcr, 6, 2); uint32_t sl2 = extract64(tcr, 33, 1); - uint32_t startlevel; + int32_t startlevel; bool ok; /* SL2 is RES0 unless DS=1 & 4kb granule. */ @@ -2604,8 +2612,8 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, ret = get_phys_addr_with_struct(env, ptw, address, access_type, result, fi); - /* If S1 fails or S2 is disabled, return early. */ - if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2, is_secure)) { + /* If S1 fails, return early. */ + if (ret) { return ret; } @@ -2731,7 +2739,8 @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, * Otherwise, a stage1+stage2 translation is just stage 1. */ ptw->in_mmu_idx = mmu_idx = s1_mmu_idx; - if (arm_feature(env, ARM_FEATURE_EL2)) { + if (arm_feature(env, ARM_FEATURE_EL2) && + !regime_translation_disabled(env, ARMMMUIdx_Stage2, is_secure)) { return get_phys_addr_twostage(env, ptw, address, access_type, result, fi); } diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 32e94153d1..cbf0081374 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7015,6 +7015,7 @@ static vaddr ppc_cpu_get_pc(CPUState *cs) return cpu->env.nip; } +#ifdef CONFIG_TCG static void ppc_restore_state_to_opc(CPUState *cs, const TranslationBlock *tb, const uint64_t *data) @@ -7023,6 +7024,7 @@ static void ppc_restore_state_to_opc(CPUState *cs, cpu->env.nip = data[0]; } +#endif /* CONFIG_TCG */ static bool ppc_cpu_has_work(CPUState *cs) { diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index a05a2ed595..94adcb766b 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2842,6 +2842,7 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, #endif #endif +#ifdef CONFIG_TCG static uint32_t helper_SIMON_LIKE_32_64(uint32_t x, uint64_t key, uint32_t lane) { const uint16_t c = 0xfffc; @@ -2924,6 +2925,7 @@ HELPER_HASH(HASHST, env->spr[SPR_HASHKEYR], true) HELPER_HASH(HASHCHK, env->spr[SPR_HASHKEYR], false) HELPER_HASH(HASHSTP, env->spr[SPR_HASHPKEYR], true) HELPER_HASH(HASHCHKP, env->spr[SPR_HASHPKEYR], false) +#endif /* CONFIG_TCG */ #if !defined(CONFIG_USER_ONLY) diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h index 74d1f87e4f..fb1adc8b21 100644 --- a/target/s390x/cpu_models.h +++ b/target/s390x/cpu_models.h @@ -24,13 +24,13 @@ struct S390CPUDef { uint8_t gen; /* hw generation identification */ uint16_t type; /* cpu type identification */ uint8_t ec_ga; /* EC GA version (on which also the BC is based) */ - uint8_t mha_pow; /* Maximum Host Adress Power, mha = 2^pow-1 */ + uint8_t mha_pow; /* maximum host address power, mha = 2^pow-1 */ uint32_t hmfai; /* hypervisor-managed facilities */ /* base/min features, must never be changed between QEMU versions */ S390FeatBitmap base_feat; /* used to init base_feat from generated data */ S390FeatInit base_init; - /* deafault features, QEMU version specific */ + /* default features, QEMU version specific */ S390FeatBitmap default_feat; /* used to init default_feat from generated data */ S390FeatInit default_init; diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index b12f18d346..053aaabb5a 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -285,7 +285,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, /* * As operand exceptions have a lower priority than access exceptions, * we check whether the memory area is writable (injecting the - * access execption if it is not) first. + * access exception if it is not) first. */ if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) { s390_program_interrupt(env, PGM_OPERAND, ra); diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c index 2cd6d062b9..fe02d82201 100644 --- a/target/s390x/tcg/excp_helper.c +++ b/target/s390x/tcg/excp_helper.c @@ -553,7 +553,7 @@ try_deliver: /* don't trigger a cpu_loop_exit(), use an interrupt instead */ cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT); } else if (cs->halted) { - /* unhalt if we had a WAIT PSW somehwere in our injection chain */ + /* unhalt if we had a WAIT PSW somewhere in our injection chain */ s390_cpu_unhalt(cpu); } } diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index 4067205405..be80b2373c 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -89,7 +89,7 @@ static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr) /* * invalid/divbyzero cannot coexist with other conditions. * overflow/underflow however can coexist with inexact, we have to - * handle it separatly. + * handle it separately. */ if (s390_exc & ~S390_IEEE_MASK_INEXACT) { if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) { diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c index 10dadb002a..71388a7119 100644 --- a/target/s390x/tcg/misc_helper.c +++ b/target/s390x/tcg/misc_helper.c @@ -333,7 +333,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1) /* same as machine type number in STORE CPU ID, but in EBCDIC */ snprintf(type, ARRAY_SIZE(type), "%X", cpu->model->def->type); ebcdic_put(sysib.sysib_111.type, type, 4); - /* model number (not stored in STORE CPU ID for z/Architecure) */ + /* model number (not stored in STORE CPU ID for z/Architecture) */ ebcdic_put(sysib.sysib_111.model, "QEMU ", 16); ebcdic_put(sysib.sysib_111.sequence, "QEMU ", 16); ebcdic_put(sysib.sysib_111.plant, "QEMU", 4); diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 2fbdab7252..1e599ac259 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -435,7 +435,7 @@ static void gen_program_exception(DisasContext *s, int code) { TCGv_i32 tmp; - /* Remember what pgm exeption this was. */ + /* Remember what pgm exception this was. */ tmp = tcg_const_i32(code); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code)); tcg_temp_free_i32(tmp); @@ -491,7 +491,7 @@ static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) /* * Note that d2 is limited to 20 bits, signed. If we crop negative - * displacements early we create larger immedate addends. + * displacements early we create larger immediate addends. */ if (b2 && x2) { tcg_gen_add_i64(tmp, regs[b2], regs[x2]); diff --git a/target/s390x/tcg/translate_vx.c.inc b/target/s390x/tcg/translate_vx.c.inc index b69c1a111c..d39ee81cd6 100644 --- a/target/s390x/tcg/translate_vx.c.inc +++ b/target/s390x/tcg/translate_vx.c.inc @@ -960,7 +960,7 @@ static DisasJumpType op_vpk(DisasContext *s, DisasOps *o) } break; case 0x94: - /* If sources and destination dont't overlap -> fast path */ + /* If sources and destination don't overlap -> fast path */ if (v1 != v2 && v1 != v3) { const uint8_t src_es = get_field(s, m4); const uint8_t dst_es = src_es - 1; @@ -2075,7 +2075,7 @@ static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o) l2 = tcg_temp_new_i64(); h2 = tcg_temp_new_i64(); - /* Multipy both even elements from v2 and v3 */ + /* Multiply both even elements from v2 and v3 */ read_vec_element_i64(l1, get_field(s, v2), 0, ES_64); read_vec_element_i64(h1, get_field(s, v3), 0, ES_64); tcg_gen_mulu2_i64(l1, h1, l1, h1); @@ -2084,7 +2084,7 @@ static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o) tcg_gen_add2_i64(l1, h1, l1, h1, l1, h1); } - /* Multipy both odd elements from v2 and v3 */ + /* Multiply both odd elements from v2 and v3 */ read_vec_element_i64(l2, get_field(s, v2), 1, ES_64); read_vec_element_i64(h2, get_field(s, v3), 1, ES_64); tcg_gen_mulu2_i64(l2, h2, l2, h2); diff --git a/tests/avocado/acpi-bits.py b/tests/avocado/acpi-bits.py index 4be663968c..898c837f26 100644 --- a/tests/avocado/acpi-bits.py +++ b/tests/avocado/acpi-bits.py @@ -134,6 +134,9 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes :avocado: tags=acpi """ + # in slower systems the test can take as long as 3 minutes to complete. + timeout = 200 + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._vm = None diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py index 571d33882a..b3e58fa309 100644 --- a/tests/avocado/boot_linux.py +++ b/tests/avocado/boot_linux.py @@ -58,13 +58,16 @@ class BootLinuxX8664(LinuxTest): self.launch_and_wait(set_up_ssh_connection=False) +# For Aarch64 we only boot KVM tests in CI as the TCG tests are very +# heavyweight. There are lighter weight distros which we use in the +# machine_aarch64_virt.py tests. class BootLinuxAarch64(LinuxTest): """ :avocado: tags=arch:aarch64 :avocado: tags=machine:virt :avocado: tags=machine:gic-version=2 """ - timeout = 240 + timeout = 720 def add_common_args(self): self.vm.add_args('-bios', @@ -73,7 +76,8 @@ class BootLinuxAarch64(LinuxTest): self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom') - def test_virt_tcg_gicv2(self): + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') + def test_fedora_cloud_tcg_gicv2(self): """ :avocado: tags=accel:tcg :avocado: tags=cpu:max @@ -86,7 +90,8 @@ class BootLinuxAarch64(LinuxTest): self.add_common_args() self.launch_and_wait(set_up_ssh_connection=False) - def test_virt_tcg_gicv3(self): + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') + def test_fedora_cloud_tcg_gicv3(self): """ :avocado: tags=accel:tcg :avocado: tags=cpu:max @@ -116,7 +121,7 @@ class BootLinuxPPC64(LinuxTest): :avocado: tags=arch:ppc64 """ - timeout = 180 + timeout = 360 def test_pseries_tcg(self): """ diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py index 4c9d551f47..ec07c64291 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -793,8 +793,8 @@ class BootLinuxConsole(LinuxKernelTest): dtb_path = '/usr/lib/linux-image-current-sunxi/sun8i-h3-orangepi-pc.dtb' dtb_path = self.extract_from_deb(deb_path, dtb_path) rootfs_url = ('http://storage.kernelci.org/images/rootfs/buildroot/' - 'kci-2019.02/armel/base/rootfs.ext2.xz') - rootfs_hash = '692510cb625efda31640d1de0a8d60e26040f061' + 'buildroot-baseline/20221116.0/armel/rootfs.ext2.xz') + rootfs_hash = 'fae32f337c7b87547b10f42599acf109da8b6d9a' rootfs_path_xz = self.fetch_asset(rootfs_url, asset_hash=rootfs_hash) rootfs_path = os.path.join(self.workdir, 'rootfs.cpio') archive.lzma_uncompress(rootfs_path_xz, rootfs_path) @@ -1029,8 +1029,8 @@ class BootLinuxConsole(LinuxKernelTest): self.wait_for_console_pattern(console_pattern) def do_test_advcal_2018(self, day, tar_hash, kernel_name, console=0): - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day' + day + '.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day' + day + '.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) self.vm.set_console(console_index=console) diff --git a/tests/avocado/machine_aarch64_virt.py b/tests/avocado/machine_aarch64_virt.py index 21848cba70..c2b2ba2cf8 100644 --- a/tests/avocado/machine_aarch64_virt.py +++ b/tests/avocado/machine_aarch64_virt.py @@ -1,4 +1,5 @@ -# Functional test that boots a Linux kernel and checks the console +# Functional test that boots a various Linux systems and checks the +# console output. # # Copyright (c) 2022 Linaro Ltd. # @@ -8,19 +9,62 @@ # SPDX-License-Identifier: GPL-2.0-or-later import time +import os from avocado_qemu import QemuSystemTest from avocado_qemu import wait_for_console_pattern from avocado_qemu import exec_command +from avocado_qemu import BUILD_DIR class Aarch64VirtMachine(QemuSystemTest): KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' + timeout = 360 def wait_for_console_pattern(self, success_message, vm=None): wait_for_console_pattern(self, success_message, failure_message='Kernel panic - not syncing', vm=vm) + # This tests the whole boot chain from EFI to Userspace + # We only boot a whole OS for the current top level CPU and GIC + # Other test profiles should use more minimal boots + def test_alpine_virt_tcg_gic_max(self): + """ + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=accel:tcg + """ + iso_url = ('https://dl-cdn.alpinelinux.org/' + 'alpine/v3.16/releases/aarch64/' + 'alpine-virt-3.16.3-aarch64.iso') + + # Alpine use sha256 so I recalculated this myself + iso_sha1 = '0683bc089486d55c91bf6607d5ecb93925769bc0' + iso_path = self.fetch_asset(iso_url, asset_hash=iso_sha1) + + self.vm.set_console() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyAMA0') + self.require_accelerator("tcg") + + self.vm.add_args("-accel", "tcg") + self.vm.add_args("-cpu", "max,pauth-impdef=on") + self.vm.add_args("-machine", + "virt,acpi=on," + "virtualization=on," + "mte=on," + "gic-version=max,iommu=smmuv3") + self.vm.add_args("-smp", "2", "-m", "1024") + self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios', + 'edk2-aarch64-code.fd')) + self.vm.add_args("-drive", f"file={iso_path},format=raw") + self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') + self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom') + + self.vm.launch() + self.wait_for_console_pattern('Welcome to Alpine Linux 3.16') + + def test_aarch64_virt(self): """ :avocado: tags=arch:aarch64 diff --git a/tests/avocado/machine_arm_canona1100.py b/tests/avocado/machine_arm_canona1100.py index 182a0b0513..a42d8b0f2b 100644 --- a/tests/avocado/machine_arm_canona1100.py +++ b/tests/avocado/machine_arm_canona1100.py @@ -23,8 +23,8 @@ class CanonA1100Machine(QemuSystemTest): :avocado: tags=machine:canon-a1100 :avocado: tags=device:pflash_cfi02 """ - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day18.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day18.tar.xz') tar_hash = '068b5fc4242b29381acee94713509f8a876e9db6' file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py index fba6527026..1fc385e1c8 100644 --- a/tests/avocado/machine_aspeed.py +++ b/tests/avocado/machine_aspeed.py @@ -12,6 +12,7 @@ from avocado_qemu import QemuSystemTest from avocado_qemu import wait_for_console_pattern from avocado_qemu import exec_command from avocado_qemu import exec_command_and_wait_for_pattern +from avocado_qemu import interrupt_interactive_console_until_pattern from avocado.utils import archive from avocado import skipIf @@ -182,6 +183,8 @@ class AST2x00Machine(QemuSystemTest): class AST2x00MachineSDK(QemuSystemTest): + EXTRA_BOOTARGS = ' quiet' + # FIXME: Although these tests boot a whole distro they are still # slower than comparable machine models. There may be some # optimisations which bring down the runtime. In the meantime they @@ -194,7 +197,7 @@ class AST2x00MachineSDK(QemuSystemTest): failure_message='Kernel panic - not syncing', vm=vm) - def do_test_arm_aspeed_sdk_start(self, image, cpu_id): + 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', @@ -202,9 +205,13 @@ class AST2x00MachineSDK(QemuSystemTest): self.vm.launch() self.wait_for_console_pattern('U-Boot 2019.04') - self.wait_for_console_pattern('## Loading kernel from FIT Image') + 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 ...') - self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id) @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_arm_ast2500_evb_sdk(self): @@ -221,7 +228,7 @@ class AST2x00MachineSDK(QemuSystemTest): archive.extract(image_path, self.workdir) self.do_test_arm_aspeed_sdk_start( - self.workdir + '/ast2500-default/image-bmc', '0x0') + self.workdir + '/ast2500-default/image-bmc') self.wait_for_console_pattern('ast2500-default login:') @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') @@ -243,7 +250,7 @@ class AST2x00MachineSDK(QemuSystemTest): self.vm.add_args('-device', 'ds1338,bus=aspeed.i2c.bus.5,address=0x32'); self.do_test_arm_aspeed_sdk_start( - self.workdir + '/ast2600-default/image-bmc', '0xf00') + self.workdir + '/ast2600-default/image-bmc') self.wait_for_console_pattern('ast2600-default login:') exec_command_and_wait_for_pattern(self, 'root', 'Password:') exec_command_and_wait_for_pattern(self, '0penBmc', 'root@ast2600-default:~#') diff --git a/tests/avocado/machine_microblaze.py b/tests/avocado/machine_microblaze.py index 4928920f96..8d0efff30d 100644 --- a/tests/avocado/machine_microblaze.py +++ b/tests/avocado/machine_microblaze.py @@ -19,8 +19,8 @@ class MicroblazeMachine(QemuSystemTest): :avocado: tags=machine:petalogix-s3adsp1800 """ - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day17.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day17.tar.xz') tar_hash = '08bf3e3bfb6b6c7ce1e54ab65d54e189f2caf13f' file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) diff --git a/tests/avocado/machine_sparc64_sun4u.py b/tests/avocado/machine_sparc64_sun4u.py index 458165500e..d333c0ae91 100644 --- a/tests/avocado/machine_sparc64_sun4u.py +++ b/tests/avocado/machine_sparc64_sun4u.py @@ -24,8 +24,8 @@ class Sun4uMachine(LinuxKernelTest): :avocado: tags=arch:sparc64 :avocado: tags=machine:sun4u """ - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day23.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day23.tar.xz') tar_hash = '142db83cd974ffadc4f75c8a5cad5bcc5722c240' file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) diff --git a/tests/avocado/ppc_mpc8544ds.py b/tests/avocado/ppc_mpc8544ds.py index 8d6a749201..b599fb1cc9 100644 --- a/tests/avocado/ppc_mpc8544ds.py +++ b/tests/avocado/ppc_mpc8544ds.py @@ -22,9 +22,9 @@ class Mpc8544dsMachine(QemuSystemTest): :avocado: tags=accel:tcg """ self.require_accelerator("tcg") - tar_url = ('https://www.qemu-advent-calendar.org' - '/2020/download/day17.tar.gz') - tar_hash = '7a5239542a7c4257aa4d3b7f6ddf08fb6775c494' + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day04.tar.xz') + tar_hash = 'f46724d281a9f30fa892d458be7beb7d34dc25f9' file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) self.vm.set_console() diff --git a/tests/avocado/ppc_virtex_ml507.py b/tests/avocado/ppc_virtex_ml507.py index 6b07686b56..a73f8ae396 100644 --- a/tests/avocado/ppc_virtex_ml507.py +++ b/tests/avocado/ppc_virtex_ml507.py @@ -22,9 +22,9 @@ class VirtexMl507Machine(QemuSystemTest): :avocado: tags=accel:tcg """ self.require_accelerator("tcg") - tar_url = ('https://www.qemu-advent-calendar.org' - '/2020/download/hippo.tar.gz') - tar_hash = '306b95bfe7d147f125aa176a877e266db8ef914a' + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day08.tar.xz') + tar_hash = '74c68f5af7a7b8f21c03097b298f3bb77ff52c1f' file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) self.vm.set_console() diff --git a/tests/avocado/replay_kernel.py b/tests/avocado/replay_kernel.py index 0b2b0dc692..00a26e4a0c 100644 --- a/tests/avocado/replay_kernel.py +++ b/tests/avocado/replay_kernel.py @@ -296,8 +296,8 @@ class ReplayKernelNormal(ReplayKernelBase): :avocado: tags=machine:vexpress-a9 """ tar_hash = '32b7677ce8b6f1471fb0059865f451169934245b' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day16.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day16.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) dtb_path = self.workdir + '/day16/vexpress-v2p-ca9.dtb' self.do_test_advcal_2018(file_path, 'winter.zImage', @@ -309,8 +309,8 @@ class ReplayKernelNormal(ReplayKernelBase): :avocado: tags=machine:mcf5208evb """ tar_hash = 'ac688fd00561a2b6ce1359f9ff6aa2b98c9a570c' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day07.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day07.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'sanity-clause.elf') @@ -321,8 +321,8 @@ class ReplayKernelNormal(ReplayKernelBase): :avocado: tags=machine:petalogix-s3adsp1800 """ tar_hash = '08bf3e3bfb6b6c7ce1e54ab65d54e189f2caf13f' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day17.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day17.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'ballerina.bin') @@ -333,8 +333,8 @@ class ReplayKernelNormal(ReplayKernelBase): :avocado: tags=cpu:e5500 """ tar_hash = '6951d86d644b302898da2fd701739c9406527fe1' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day19.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day19.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'uImage') @@ -344,8 +344,8 @@ class ReplayKernelNormal(ReplayKernelBase): :avocado: tags=machine:or1k-sim """ tar_hash = '20334cdaf386108c530ff0badaecc955693027dd' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day20.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day20.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'vmlinux') @@ -355,8 +355,8 @@ class ReplayKernelNormal(ReplayKernelBase): :avocado: tags=machine:10m50-ghrd """ tar_hash = 'e4251141726c412ac0407c5a6bceefbbff018918' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day14.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day14.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'vmlinux.elf') @@ -366,8 +366,8 @@ class ReplayKernelNormal(ReplayKernelBase): :avocado: tags=machine:g3beige """ tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day15.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day15.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'invaders.elf', args=('-M', 'graphics=off')) @@ -378,8 +378,8 @@ class ReplayKernelNormal(ReplayKernelBase): :avocado: tags=machine:mac99 """ tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day15.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day15.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'invaders.elf', args=('-M', 'graphics=off')) @@ -390,8 +390,8 @@ class ReplayKernelNormal(ReplayKernelBase): :avocado: tags=machine:SS-20 """ tar_hash = 'b18550d5d61c7615d989a06edace051017726a9f' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day11.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day11.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'zImage.elf') @@ -402,8 +402,8 @@ class ReplayKernelNormal(ReplayKernelBase): :avocado: tags=cpu:dc233c """ tar_hash = '49e88d9933742f0164b60839886c9739cb7a0d34' - tar_url = ('https://www.qemu-advent-calendar.org' - '/2018/download/day02.tar.xz') + tar_url = ('https://qemu-advcal.gitlab.io' + '/qac-best-of-multiarch/download/day02.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) self.do_test_advcal_2018(file_path, 'santas-sleigh-ride.elf') diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index c87f14477a..fc7a3b7e71 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -184,6 +184,7 @@ docker: @echo ' TARGET_LIST=a,b,c Override target list in builds.' @echo ' EXTRA_CONFIGURE_OPTS="..."' @echo ' Extra configure options.' + @echo ' TEST_COMMAND="..." Override the default `make check` target.' @echo ' IMAGES="a b c ..": Restrict available images to subset.' @echo ' TESTS="x y z .." Restrict available tests to subset.' @echo ' J=[0..9]* Overrides the -jN parameter for make commands' @@ -230,6 +231,7 @@ docker-run: docker-qemu-src $(if $(NETWORK),$(if $(subst $(NETWORK),,1),--net=$(NETWORK)),--net=none) \ -e TARGET_LIST=$(subst $(SPACE),$(COMMA),$(TARGET_LIST)) \ -e EXTRA_CONFIGURE_OPTS="$(EXTRA_CONFIGURE_OPTS)" \ + -e TEST_COMMAND="$(TEST_COMMAND)" \ -e V=$V -e J=$J -e DEBUG=$(DEBUG) \ -e SHOW_ENV=$(SHOW_ENV) \ $(if $(NOUSER),, \ diff --git a/tests/docker/common.rc b/tests/docker/common.rc index e6f8cee0d6..9a33df2832 100755 --- a/tests/docker/common.rc +++ b/tests/docker/common.rc @@ -63,12 +63,12 @@ check_qemu() { # default to make check unless the caller specifies if [ $# = 0 ]; then - INVOCATION="check" + INVOCATION="${TEST_COMMAND:-make $MAKEFLAGS check}" else - INVOCATION="$@" + INVOCATION="make $MAKEFLAGS $@" fi - make $MAKEFLAGS $INVOCATION + $INVOCATION } test_fail() diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci -Subproject d40e203631eb3eacee17e8cf8fd20aa5152db62 +Subproject e3eb28cf2e17fbcf7fe7e19505ee432b8ec5bbb diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index ce0b24c0b1..fa966e4009 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -176,7 +176,7 @@ try: # generate_cirrus("freebsd-12") generate_cirrus("freebsd-13") - generate_cirrus("macos-11") + generate_cirrus("macos-12") sys.exit(0) except Exception as ex: diff --git a/tests/qtest/qom-test.c b/tests/qtest/qom-test.c index 7b871b2a31..13510bc349 100644 --- a/tests/qtest/qom-test.c +++ b/tests/qtest/qom-test.c @@ -20,6 +20,7 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) QDict *response, *tuple, *tmp; QList *list; QListEntry *entry; + GSList *children = NULL, *links = NULL; g_test_message("Obtaining properties of %s", path); response = qtest_qmp(qts, "{ 'execute': 'qom-list'," @@ -41,11 +42,14 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) if (is_child || is_link) { child_path = g_strdup_printf("%s/%s", path, qdict_get_str(tuple, "name")); - test_properties(qts, child_path, is_child); - g_free(child_path); + if (is_child) { + children = g_slist_prepend(children, child_path); + } else { + links = g_slist_prepend(links, child_path); + } } else { const char *prop = qdict_get_str(tuple, "name"); - g_test_message("Testing property %s.%s", path, prop); + g_test_message("-> %s", prop); tmp = qtest_qmp(qts, "{ 'execute': 'qom-get'," " 'arguments': { 'path': %s, 'property': %s } }", @@ -55,6 +59,18 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) qobject_unref(tmp); } } + + while (links) { + test_properties(qts, links->data, false); + g_free(links->data); + links = g_slist_delete_link(links, links); + } + while (children) { + test_properties(qts, children->data, true); + g_free(children->data); + children = g_slist_delete_link(children, children); + } + qobject_unref(response); } diff --git a/tools/virtiofsd/passthrough_seccomp.c b/tools/virtiofsd/passthrough_seccomp.c index 888295c073..0033dab493 100644 --- a/tools/virtiofsd/passthrough_seccomp.c +++ b/tools/virtiofsd/passthrough_seccomp.c @@ -110,6 +110,7 @@ static const int syscall_allowlist[] = { #endif SCMP_SYS(set_robust_list), SCMP_SYS(setxattr), + SCMP_SYS(sigreturn), SCMP_SYS(symlinkat), SCMP_SYS(syncfs), SCMP_SYS(time), /* Rarely needed, except on static builds */ diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 35f917ceb1..e84431790c 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -341,7 +341,7 @@ void gd_egl_flush(DisplayChangeListener *dcl, VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); GtkWidget *area = vc->gfx.drawing_area; - if (vc->gfx.guest_fb.dmabuf) { + if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) { graphic_hw_gl_block(vc->gfx.dcl.con, true); vc->gfx.guest_fb.dmabuf->draw_submitted = true; gtk_widget_queue_draw_area(area, x, y, w, h); diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index 682638a197..7696df1f6b 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -278,7 +278,7 @@ void gd_gl_area_scanout_flush(DisplayChangeListener *dcl, { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); - if (vc->gfx.guest_fb.dmabuf) { + if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) { graphic_hw_gl_block(vc->gfx.dcl.con, true); vc->gfx.guest_fb.dmabuf->draw_submitted = true; } @@ -2403,7 +2403,9 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) opts->u.gtk.show_tabs) { gtk_menu_item_activate(GTK_MENU_ITEM(s->show_tabs_item)); } +#ifdef CONFIG_GTK_CLIPBOARD gd_clipboard_init(s); +#endif /* CONFIG_GTK_CLIPBOARD */ } static void early_gtk_display_init(DisplayOptions *opts) diff --git a/ui/meson.build b/ui/meson.build index ec13949776..c1b137bf33 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -97,7 +97,10 @@ if gtk.found() softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('win32-kbd-hook.c')) gtk_ss = ss.source_set() - gtk_ss.add(gtk, vte, pixman, files('gtk.c', 'gtk-clipboard.c')) + gtk_ss.add(gtk, vte, pixman, files('gtk.c')) + if have_gtk_clipboard + gtk_ss.add(files('gtk-clipboard.c')) + endif gtk_ss.add(when: x11, if_true: files('x_keymap.c')) gtk_ss.add(when: opengl, if_true: files('gtk-gl-area.c')) gtk_ss.add(when: [x11, opengl], if_true: files('gtk-egl.c')) diff --git a/util/bitmap.c b/util/bitmap.c index f81d8057a7..8d12e90a5a 100644 --- a/util/bitmap.c +++ b/util/bitmap.c @@ -240,6 +240,51 @@ void bitmap_clear(unsigned long *map, long start, long nr) } } +bool bitmap_test_and_clear(unsigned long *map, long start, long nr) +{ + unsigned long *p = map + BIT_WORD(start); + const long size = start + nr; + int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG); + unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); + bool dirty = false; + + assert(start >= 0 && nr >= 0); + + /* First word */ + if (nr - bits_to_clear > 0) { + if ((*p) & mask_to_clear) { + dirty = true; + } + *p &= ~mask_to_clear; + nr -= bits_to_clear; + bits_to_clear = BITS_PER_LONG; + p++; + } + + /* Full words */ + if (bits_to_clear == BITS_PER_LONG) { + while (nr >= BITS_PER_LONG) { + if (*p) { + dirty = true; + *p = 0; + } + nr -= BITS_PER_LONG; + p++; + } + } + + /* Last word */ + if (nr) { + mask_to_clear &= BITMAP_LAST_WORD_MASK(size); + if ((*p) & mask_to_clear) { + dirty = true; + } + *p &= ~mask_to_clear; + } + + return dirty; +} + bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr) { unsigned long *p = map + BIT_WORD(start); |