From 41a6620c91db5724ab44495294336d2a689bd2fd Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 22 Oct 2025 17:31:09 -0400 Subject: [PATCH 01/22] scripts/device-crash-test: fix spurious EOFError messages When the QMP library was updated to match the standalone repository in 094ded52, I neglected to update the logging filter(s) in device-crash-test, which allowed the spurious messages to leak through. Update the log filter to re-suppress these messages. Fixes: 094ded52 Reported-by: Thomas Huth Signed-off-by: John Snow Message-ID: <20251022213109.395149-1-jsnow@redhat.com> Signed-off-by: Thomas Huth --- scripts/device-crash-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/device-crash-test b/scripts/device-crash-test index 1ecb9663ae..c1576e8b96 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test @@ -527,7 +527,7 @@ def main(): # Async QMP, when in use, is chatty about connection failures. # This script knowingly generates a ton of connection errors. # Silence this logger. - logging.getLogger('qemu.qmp.qmp_client').setLevel(logging.CRITICAL) + logging.getLogger('qemu.qmp.protocol').setLevel(logging.CRITICAL) fatal_failures = [] wl_stats = {} From 1a6ccf45eb372fd1d687fe47009151d004099985 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 13 Oct 2025 15:38:03 +0200 Subject: [PATCH 02/22] tests/functional: Fix problems in asset.py reported by pylint The "raise" without an Exception was a real problem, the other spots are rather cosmetics. Signed-off-by: Thomas Huth Message-ID: <20251015095454.1575318-2-thuth@redhat.com> --- tests/functional/qemu_test/asset.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py index ab3a7bb591..bae40765ce 100644 --- a/tests/functional/qemu_test/asset.py +++ b/tests/functional/qemu_test/asset.py @@ -112,7 +112,7 @@ class Asset: return False self.log.debug("Time out while waiting for %s!", tmp_cache_file) - raise + raise TimeoutError(f"Time out while waiting for {tmp_cache_file}") def _save_time_stamp(self): ''' @@ -141,7 +141,7 @@ class Asset: self.log.info("Downloading %s to %s...", self.url, self.cache_file) tmp_cache_file = self.cache_file.with_suffix(".download") - for retries in range(3): + for _retries in range(3): try: with tmp_cache_file.open("xb") as dst: with urllib.request.urlopen(self.url) as resp: @@ -181,7 +181,7 @@ class Asset: # server or networking problem if e.code == 404: raise AssetError(self, "Unable to download: " - "HTTP error %d" % e.code) + "HTTP error %d" % e.code) from e continue except URLError as e: # This is typically a network/service level error @@ -190,7 +190,7 @@ class Asset: self.log.error("Unable to download %s: URL error %s", self.url, e.reason) raise AssetError(self, "Unable to download: URL error %s" % - e.reason, transient=True) + e.reason, transient=True) from e except ConnectionError as e: # A socket connection failure, such as dropped conn # or refused conn @@ -201,7 +201,7 @@ class Asset: except Exception as e: tmp_cache_file.unlink() raise AssetError(self, "Unable to download: %s" % e, - transient=True) + transient=True) from e if not os.path.exists(tmp_cache_file): raise AssetError(self, "Download retries exceeded", transient=True) @@ -214,7 +214,6 @@ class Asset: self.hash.encode('utf8')) except Exception as e: self.log.debug("Unable to set xattr on %s: %s", tmp_cache_file, e) - pass if not self._check(tmp_cache_file): tmp_cache_file.unlink() @@ -224,9 +223,10 @@ class Asset: # Remove write perms to stop tests accidentally modifying them os.chmod(self.cache_file, stat.S_IRUSR | stat.S_IRGRP) - self.log.info("Cached %s at %s" % (self.url, self.cache_file)) + self.log.info("Cached %s at %s", self.url, self.cache_file) return str(self.cache_file) + @staticmethod def precache_test(test): log = logging.getLogger('qemu-test') log.setLevel(logging.DEBUG) @@ -237,16 +237,17 @@ class Asset: handler.setFormatter(formatter) log.addHandler(handler) for name, asset in vars(test.__class__).items(): - if name.startswith("ASSET_") and type(asset) == Asset: + if name.startswith("ASSET_") and isinstance(asset, Asset): try: asset.fetch() except AssetError as e: if not e.transient: raise - log.error("%s: skipping asset precache" % e) + log.error("%s: skipping asset precache", e) log.removeHandler(handler) + @staticmethod def precache_suite(suite): for test in suite: if isinstance(test, unittest.TestSuite): @@ -254,9 +255,10 @@ class Asset: elif isinstance(test, unittest.TestCase): Asset.precache_test(test) - def precache_suites(path, cacheTstamp): + @staticmethod + def precache_suites(path, cache_tstamp): loader = unittest.loader.defaultTestLoader tests = loader.loadTestsFromNames([path], None) - with open(cacheTstamp, "w") as fh: + with open(cache_tstamp, "w", encoding='utf-8'): Asset.precache_suite(tests) From 9641b013573eed1830d8998953b4c4d984913b13 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 15 Oct 2025 11:54:50 +0200 Subject: [PATCH 03/22] tests/functional: Fix problems in decorators.py reported by pylint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documentation strings should follow the function definition lines, not precede them. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20251015095454.1575318-3-thuth@redhat.com> --- tests/functional/qemu_test/decorators.py | 184 +++++++++++------------ 1 file changed, 91 insertions(+), 93 deletions(-) diff --git a/tests/functional/qemu_test/decorators.py b/tests/functional/qemu_test/decorators.py index b239295804..807418359a 100644 --- a/tests/functional/qemu_test/decorators.py +++ b/tests/functional/qemu_test/decorators.py @@ -10,136 +10,134 @@ from unittest import skipIf, skipUnless from .cmd import which -''' -Decorator to skip execution of a test if the provided -environment variables are not set. -Example: - @skipIfMissingEnv("QEMU_ENV_VAR0", "QEMU_ENV_VAR1") -''' def skipIfMissingEnv(*vars_): + ''' + Decorator to skip execution of a test if the provided + environment variables are not set. + Example: + + @skipIfMissingEnv("QEMU_ENV_VAR0", "QEMU_ENV_VAR1") + ''' missing_vars = [] for var in vars_: - if os.getenv(var) == None: + if os.getenv(var) is None: missing_vars.append(var) - has_vars = True if len(missing_vars) == 0 else False + has_vars = len(missing_vars) == 0 return skipUnless(has_vars, f"Missing env var(s): {', '.join(missing_vars)}") -''' - -Decorator to skip execution of a test if the list -of command binaries is not available in $PATH. -Example: - - @skipIfMissingCommands("mkisofs", "losetup") -''' def skipIfMissingCommands(*args): + ''' + Decorator to skip execution of a test if the list + of command binaries is not available in $PATH. + Example: + + @skipIfMissingCommands("mkisofs", "losetup") + ''' has_cmds = True for cmd in args: - if not which(cmd): - has_cmds = False - break + if not which(cmd): + has_cmds = False + break return skipUnless(has_cmds, 'required command(s) "%s" not installed' % ", ".join(args)) -''' -Decorator to skip execution of a test if the current -host operating system does match one of the prohibited -ones. -Example - - @skipIfOperatingSystem("Linux", "Darwin") -''' def skipIfOperatingSystem(*args): + ''' + Decorator to skip execution of a test if the current host + operating system does match one of the prohibited ones. + Example: + + @skipIfOperatingSystem("Linux", "Darwin") + ''' return skipIf(platform.system() in args, 'running on an OS (%s) that is not able to run this test' % ", ".join(args)) -''' -Decorator to skip execution of a test if the current -host machine does not match one of the permitted -machines. -Example - - @skipIfNotMachine("x86_64", "aarch64") -''' def skipIfNotMachine(*args): + ''' + Decorator to skip execution of a test if the current + host machine does not match one of the permitted machines. + Example: + + @skipIfNotMachine("x86_64", "aarch64") + ''' return skipUnless(platform.machine() in args, 'not running on one of the required machine(s) "%s"' % ", ".join(args)) -''' -Decorator to skip execution of flaky tests, unless -the $QEMU_TEST_FLAKY_TESTS environment variable is set. -A bug URL must be provided that documents the observed -failure behaviour, so it can be tracked & re-evaluated -in future. - -Historical tests may be providing "None" as the bug_url -but this should not be done for new test. - -Example: - - @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN") -''' def skipFlakyTest(bug_url): + ''' + Decorator to skip execution of flaky tests, unless + the $QEMU_TEST_FLAKY_TESTS environment variable is set. + A bug URL must be provided that documents the observed + failure behaviour, so it can be tracked & re-evaluated + in future. + + Historical tests may be providing "None" as the bug_url + but this should not be done for new test. + + Example: + + @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN") + ''' if bug_url is None: bug_url = "FIXME: reproduce flaky test and file bug report or remove" return skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), f'Test is unstable: {bug_url}') -''' -Decorator to skip execution of tests which are likely -to execute untrusted commands on the host, or commands -which process untrusted code, unless the -$QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set. -Example: - - @skipUntrustedTest() -''' def skipUntrustedTest(): + ''' + Decorator to skip execution of tests which are likely + to execute untrusted commands on the host, or commands + which process untrusted code, unless the + $QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set. + Example: + + @skipUntrustedTest() + ''' return skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'Test runs untrusted code / processes untrusted data') -''' -Decorator to skip execution of tests which need large -data storage (over around 500MB-1GB mark) on the host, -unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment -variable is set - -Example: - - @skipBigDataTest() -''' def skipBigDataTest(): + ''' + Decorator to skip execution of tests which need large + data storage (over around 500MB-1GB mark) on the host, + unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment + variable is set + + Example: + + @skipBigDataTest() + ''' return skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'Test requires large host storage space') -''' -Decorator to skip execution of tests which have a really long -runtime (and might e.g. time out if QEMU has been compiled with -debugging enabled) unless the $QEMU_TEST_ALLOW_SLOW -environment variable is set - -Example: - - @skipSlowTest() -''' def skipSlowTest(): + ''' + Decorator to skip execution of tests which have a really long + runtime (and might e.g. time out if QEMU has been compiled with + debugging enabled) unless the $QEMU_TEST_ALLOW_SLOW + environment variable is set + + Example: + + @skipSlowTest() + ''' return skipUnless(os.getenv('QEMU_TEST_ALLOW_SLOW'), 'Test has a very long runtime and might time out') -''' -Decorator to skip execution of a test if the list -of python imports is not available. -Example: - - @skipIfMissingImports("numpy", "cv2") -''' def skipIfMissingImports(*args): + ''' + Decorator to skip execution of a test if the list + of python imports is not available. + Example: + + @skipIfMissingImports("numpy", "cv2") + ''' has_imports = True for impname in args: try: @@ -151,15 +149,15 @@ def skipIfMissingImports(*args): return skipUnless(has_imports, 'required import(s) "%s" not installed' % ", ".join(args)) -''' -Decorator to skip execution of a test if the system's -locked memory limit is below the required threshold. -Takes required locked memory threshold in kB. -Example: - - @skipLockedMemoryTest(2_097_152) -''' def skipLockedMemoryTest(locked_memory): + ''' + Decorator to skip execution of a test if the system's + locked memory limit is below the required threshold. + Takes required locked memory threshold in kB. + Example: + + @skipLockedMemoryTest(2_097_152) + ''' # get memlock hard limit in bytes _, ulimit_memory = resource.getrlimit(resource.RLIMIT_MEMLOCK) From 72f6657402145f9019380c6d96e3f7f601bbb271 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 13 Oct 2025 16:18:14 +0200 Subject: [PATCH 04/22] tests/functional: Fix problems in linuxkernel.py reported by pylint Use proper indentation here. Message-ID: <20251015095454.1575318-3-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/functional/qemu_test/linuxkernel.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/functional/qemu_test/linuxkernel.py b/tests/functional/qemu_test/linuxkernel.py index c4767527da..eb10a81335 100644 --- a/tests/functional/qemu_test/linuxkernel.py +++ b/tests/functional/qemu_test/linuxkernel.py @@ -83,12 +83,12 @@ class LinuxKernelTest(QemuSystemTest): self.vm.set_console(console_index=console_index) self.vm.add_args('-kernel', kernel) if initrd: - self.vm.add_args('-initrd', initrd) + self.vm.add_args('-initrd', initrd) if dtb: - self.vm.add_args('-dtb', dtb) + self.vm.add_args('-dtb', dtb) self.vm.launch() if wait_for: - self.wait_for_console_pattern(wait_for) + self.wait_for_console_pattern(wait_for) def check_http_download(self, filename, hashsum, guestport=8080, pythoncmd='python3 -m http.server'): From de52392666ac685e537b62d1d38723c568fb6a4d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 15 Oct 2025 11:54:53 +0200 Subject: [PATCH 05/22] tests/functional: Fix problems in uncompress.py reported by pylint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - put the doc strings in the right locations (after the "def" line) - use isinstance() instead of checking via type() Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20251015095454.1575318-6-thuth@redhat.com> --- tests/functional/qemu_test/uncompress.py | 44 ++++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/functional/qemu_test/uncompress.py b/tests/functional/qemu_test/uncompress.py index b7ef8f759b..5bbdf8fe32 100644 --- a/tests/functional/qemu_test/uncompress.py +++ b/tests/functional/qemu_test/uncompress.py @@ -58,20 +58,20 @@ def zstd_uncompress(zstd_path, output_path): os.chmod(output_path, stat.S_IRUSR | stat.S_IWUSR) -''' -@params compressed: filename, Asset, or file-like object to uncompress -@params uncompressed: filename to uncompress into -@params format: optional compression format (gzip, lzma) - -Uncompresses @compressed into @uncompressed - -If @format is None, heuristics will be applied to guess the format -from the filename or Asset URL. @format must be non-None if @uncompressed -is a file-like object. - -Returns the fully qualified path to the uncompessed file -''' def uncompress(compressed, uncompressed, format=None): + ''' + @params compressed: filename, Asset, or file-like object to uncompress + @params uncompressed: filename to uncompress into + @params format: optional compression format (gzip, lzma) + + Uncompresses @compressed into @uncompressed + + If @format is None, heuristics will be applied to guess the + format from the filename or Asset URL. @format must be non-None + if @uncompressed is a file-like object. + + Returns the fully qualified path to the uncompessed file + ''' if format is None: format = guess_uncompress_format(compressed) @@ -84,19 +84,19 @@ def uncompress(compressed, uncompressed, format=None): else: raise Exception(f"Unknown compression format {format}") -''' -@params compressed: filename, Asset, or file-like object to guess - -Guess the format of @compressed, raising an exception if -no format can be determined -''' def guess_uncompress_format(compressed): - if type(compressed) == Asset: + ''' + @params compressed: filename, Asset, or file-like object to guess + + Guess the format of @compressed, raising an exception if + no format can be determined + ''' + if isinstance(compressed, Asset): compressed = urlparse(compressed.url).path - elif type(compressed) != str: + elif not isinstance(compressed, str): raise Exception(f"Unable to guess compression cformat for {compressed}") - (name, ext) = os.path.splitext(compressed) + (_name, ext) = os.path.splitext(compressed) if ext == ".xz": return "xz" elif ext == ".gz": From 45117fd75e55998528d63cb25e06f3ce05922283 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 15 Oct 2025 11:54:54 +0200 Subject: [PATCH 06/22] tests/functional: Fix problems in utils.py reported by pylint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - put the doc strings in the right locations (after the "def" line) - use the right indentation (4 spaces) Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20251015095454.1575318-7-thuth@redhat.com> --- tests/functional/qemu_test/utils.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py index e7c8de8165..826c267785 100644 --- a/tests/functional/qemu_test/utils.py +++ b/tests/functional/qemu_test/utils.py @@ -17,10 +17,10 @@ def get_usernet_hostfwd_port(vm): res = vm.cmd('human-monitor-command', command_line='info usernet') return get_info_usernet_hostfwd_port(res) -""" -Round up to next power of 2 -""" def pow2ceil(x): + """ + Round up to next power of 2 + """ return 1 if x == 0 else 2**(x - 1).bit_length() def file_truncate(path, size): @@ -28,12 +28,12 @@ def file_truncate(path, size): with open(path, 'ab+') as fd: fd.truncate(size) -""" -Expand file size to next power of 2 -""" def image_pow2ceil_expand(path): - size = os.path.getsize(path) - size_aligned = pow2ceil(size) - if size != size_aligned: - with open(path, 'ab+') as fd: - fd.truncate(size_aligned) + """ + Expand file size to next power of 2 + """ + size = os.path.getsize(path) + size_aligned = pow2ceil(size) + if size != size_aligned: + with open(path, 'ab+') as fd: + fd.truncate(size_aligned) From 356bc343e8ad01ed3db5faad8742717393bfab01 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 24 Oct 2025 14:40:16 +0200 Subject: [PATCH 07/22] tests/functional/arm/test_aspeed_ast1030: Remove unused import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This file does not use LinuxKernelTest directly (but AspeedTest), so we can remove this unnecessary import here. Reviewed-by: Cédric Le Goater Signed-off-by: Thomas Huth Message-ID: <20251024124016.799687-1-thuth@redhat.com> --- tests/functional/arm/test_aspeed_ast1030.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/functional/arm/test_aspeed_ast1030.py b/tests/functional/arm/test_aspeed_ast1030.py index 60e2b0251c..d1822edd8f 100755 --- a/tests/functional/arm/test_aspeed_ast1030.py +++ b/tests/functional/arm/test_aspeed_ast1030.py @@ -6,9 +6,8 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import LinuxKernelTest, Asset from aspeed import AspeedTest -from qemu_test import exec_command_and_wait_for_pattern +from qemu_test import Asset, exec_command_and_wait_for_pattern class AST1030Machine(AspeedTest): From ee7c35e77f214c39340679ffb335f25527d134d3 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 25 Oct 2025 19:58:03 +0300 Subject: [PATCH 08/22] tests/functional/.../testcase.py: better socketdir cleanup TemporaryDirectory prefer explicit call to .cleanup() (or use context manager). Otherwise it may produce a warning like: /usr/lib/python3.10/tempfile.py:1008: \ ResourceWarning: Implicitly cleaning up \ Currently, the only test using socket_dir() is tests/functional/x86_64/test_vfio_user_client.py, and it does print this warning, at least with python 3.10.12. With this commit, the warning disappears. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Thomas Huth Message-ID: <20251025165809.930670-2-vsementsov@yandex-team.ru> Signed-off-by: Thomas Huth --- tests/functional/qemu_test/testcase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 2c0abde395..a122acb560 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -233,7 +233,7 @@ class QemuBaseTest(unittest.TestCase): if "QEMU_TEST_KEEP_SCRATCH" not in os.environ: shutil.rmtree(self.workdir) if self.socketdir is not None: - shutil.rmtree(self.socketdir.name) + self.socketdir.cleanup() self.socketdir = None self.machinelog.removeHandler(self._log_fh) self.log.removeHandler(self._log_fh) From 0468ddb27fdf782b0fe0ed916cdbb2c3aa653ab5 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Sat, 25 Oct 2025 19:58:04 +0300 Subject: [PATCH 09/22] MAINTAINERS: fix functional tests section Without "S: Maintained", ./scripts/get_maintainer.pl shows "unknown" role instead of "maintainer" for "M: " entry, it's confusing. I really hope that functional tests are maintained:) Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Thomas Huth Message-ID: <20251025165809.930670-3-vsementsov@yandex-team.ru> Signed-off-by: Thomas Huth --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index a6a1d36f52..71c86ee8ce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4412,6 +4412,7 @@ Functional testing framework M: Thomas Huth R: Philippe Mathieu-Daudé R: Daniel P. Berrange +S: Maintained F: docs/devel/testing/functional.rst F: scripts/clean_functional_cache.py F: tests/functional/qemu_test/ From 053a106f67ad7553455868a6a4510a8b0ec692c8 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 27 Oct 2025 12:23:47 +0100 Subject: [PATCH 10/22] tests/functional/migration: Fix bad indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pylint complains about bad indentation in two lines. Use 12 spaces instead of 11 spaces to get it right. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20251027112347.54190-1-thuth@redhat.com> --- tests/functional/migration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functional/migration.py b/tests/functional/migration.py index 0739554483..2bfb1f7790 100644 --- a/tests/functional/migration.py +++ b/tests/functional/migration.py @@ -30,11 +30,11 @@ class MigrationTest(QemuSystemTest): end = time.monotonic() + self.timeout while time.monotonic() < end and not self.migration_finished(src_vm): - time.sleep(0.1) + time.sleep(0.1) end = time.monotonic() + self.timeout while time.monotonic() < end and not self.migration_finished(dst_vm): - time.sleep(0.1) + time.sleep(0.1) self.assertEqual(src_vm.cmd('query-migrate')['status'], 'completed') self.assertEqual(dst_vm.cmd('query-migrate')['status'], 'completed') From 65530a2f09fd06359538411b67d3660430f85d6c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 29 Oct 2025 09:05:02 +0100 Subject: [PATCH 11/22] tests/functional/ppc64/test_mac99: Fix style issues reported by pylint Pylint complained about lines being too long here, and mac99Test not following the usual CamelCase capitalization. Reviewed-by: Manos Pitsidianakis Signed-off-by: Thomas Huth Message-ID: <20251029080502.52938-1-thuth@redhat.com> --- tests/functional/ppc64/test_mac99.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/functional/ppc64/test_mac99.py b/tests/functional/ppc64/test_mac99.py index dfd9c01371..a3261a8330 100755 --- a/tests/functional/ppc64/test_mac99.py +++ b/tests/functional/ppc64/test_mac99.py @@ -7,14 +7,16 @@ from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern -class mac99Test(LinuxKernelTest): +class Mac99Test(LinuxKernelTest): ASSET_BR2_MAC99_LINUX = Asset( - 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/vmlinux', + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main' + '/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/vmlinux'), 'd59307437e4365f2cced0bbd1b04949f7397b282ef349b7cafd894d74aadfbff') ASSET_BR2_MAC99_ROOTFS = Asset( - 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main//buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/rootfs.ext2', + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main' + '/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/rootfs.ext2'), 'bbd5fd8af62f580bc4e585f326fe584e22856572633a8333178ea6d4ed4955a4') def test_ppc64_mac99_buildroot(self): From 38e272e595ea85a4dd927253784bf8db996fa360 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 29 Oct 2025 09:18:05 +0100 Subject: [PATCH 12/22] tests/functional/rx/test_gdbsim: Remove unused variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove/comment some unused variables to make pylint happy. Reviewed-by: Daniel P. Berrangé Signed-off-by: Thomas Huth Message-ID: <20251029081805.63147-1-thuth@redhat.com> --- tests/functional/rx/test_gdbsim.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/functional/rx/test_gdbsim.py b/tests/functional/rx/test_gdbsim.py index 49245793e1..d31f9a42d6 100755 --- a/tests/functional/rx/test_gdbsim.py +++ b/tests/functional/rx/test_gdbsim.py @@ -17,9 +17,6 @@ from qemu_test import wait_for_console_pattern, skipFlakyTest class RxGdbSimMachine(QemuSystemTest): - timeout = 30 - KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' - ASSET_UBOOT = Asset( ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/' 'u-boot.bin'), @@ -47,7 +44,7 @@ class RxGdbSimMachine(QemuSystemTest): self.vm.launch() uboot_version = 'U-Boot 2016.05-rc3-23705-ga1ef3c71cb-dirty' wait_for_console_pattern(self, uboot_version) - gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)' + #gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)' # FIXME limit baudrate on chardev, else we type too fast # https://gitlab.com/qemu-project/qemu/-/issues/2691 #exec_command_and_wait_for_pattern(self, 'version', gcc_version) @@ -63,7 +60,6 @@ class RxGdbSimMachine(QemuSystemTest): kernel_path = self.ASSET_KERNEL.fetch() self.vm.set_console() - kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'earlycon' self.vm.add_args('-kernel', kernel_path, '-dtb', dtb_path, '-no-reboot') From 5684fb080528abbcb10a2e1c9aaceea13af5cecc Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 29 Oct 2025 09:15:14 +0100 Subject: [PATCH 13/22] tests/functional/x86_64/test_acpi_bits: Silence warnings reported by pylint Pylint complains about too many positional arguments for the __init__ function of the QEMUBitsMachine class, use a "*" to enforce argument passing by names instead (which the calling sites are doing here already). Second, use lazy logging when calling self.log.info() with a "%s" format string, and drop a superfluous "else:" that is not necessary after a "raise" statement. Reviewed-by: Zhao Liu Signed-off-by: Thomas Huth Message-ID: <20251029081514.60802-1-thuth@redhat.com> --- tests/functional/x86_64/test_acpi_bits.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional/x86_64/test_acpi_bits.py b/tests/functional/x86_64/test_acpi_bits.py index 9a2816533d..ec716d643b 100755 --- a/tests/functional/x86_64/test_acpi_bits.py +++ b/tests/functional/x86_64/test_acpi_bits.py @@ -57,6 +57,7 @@ class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods """ def __init__(self, binary: str, + *, args: Sequence[str] = (), wrapper: Sequence[str] = (), name: Optional[str] = None, @@ -225,7 +226,7 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True) - self.log.info("grub-mkrescue output %s" % proc.stdout) + self.log.info("grub-mkrescue output %s", proc.stdout) else: subprocess.check_call([mkrescue_script, '-o', iso_file, bits_dir], @@ -287,9 +288,8 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute except AssertionError as e: self._print_log(log) raise e - else: - if os.getenv('V') or os.getenv('BITS_DEBUG'): - self._print_log(log) + if os.getenv('V') or os.getenv('BITS_DEBUG'): + self._print_log(log) def tearDown(self): """ From 8e833cbf119f88ca194ed2298758faa9edafc931 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 29 Oct 2025 08:53:42 +0100 Subject: [PATCH 14/22] tests/functional/x86_64/test_virtio_balloon: Fix cosmetic issues from pylint Pylint complains about some style issues in this file: Unused variables should be marked with an underscore, "when > then and when < now" can be simplified to "now > when > then" and expectData doesn't conform to the usual snake_case naming style. Reviewed-by: Zhao Liu Reviewed-by: Manos Pitsidianakis Signed-off-by: Thomas Huth Message-ID: <20251029075342.47335-1-thuth@redhat.com> --- tests/functional/x86_64/test_virtio_balloon.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional/x86_64/test_virtio_balloon.py b/tests/functional/x86_64/test_virtio_balloon.py index 5877b6c408..7a579e0d69 100755 --- a/tests/functional/x86_64/test_virtio_balloon.py +++ b/tests/functional/x86_64/test_virtio_balloon.py @@ -66,7 +66,7 @@ class VirtioBalloonx86(QemuSystemTest): when = ret.get('last-update') assert when == 0 stats = ret.get('stats') - for name, val in stats.items(): + for _name, val in stats.items(): assert val == UNSET_STATS_VALUE def assert_running_stats(self, then): @@ -87,10 +87,10 @@ class VirtioBalloonx86(QemuSystemTest): now = time.time() - assert when > then and when < now + assert now > when > then stats = ret.get('stats') # Stat we expect this particular Kernel to have set - expectData = [ + expect_data = [ "stat-available-memory", "stat-disk-caches", "stat-free-memory", @@ -103,7 +103,7 @@ class VirtioBalloonx86(QemuSystemTest): "stat-total-memory", ] for name, val in stats.items(): - if name in expectData: + if name in expect_data: assert val != UNSET_STATS_VALUE else: assert val == UNSET_STATS_VALUE From ec5a5f8b6d24adc94aa44afbfcb3063192424c54 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 29 Oct 2025 15:19:46 +0100 Subject: [PATCH 15/22] tests/functional/ppc64: Fix class names to silence pylint warnings Pylint complains about inconsistent CamelCase names here, so let's slightly change the names to make pylint happy again. In the sam460ex test, also split a line where pylint was complaining about it being too long. Reviewed-by: Glenn Miles Signed-off-by: Thomas Huth Message-ID: <20251029141946.86110-1-thuth@redhat.com> --- tests/functional/ppc/test_74xx.py | 2 +- tests/functional/ppc/test_sam460ex.py | 5 +++-- tests/functional/ppc64/test_powernv.py | 2 +- tests/functional/ppc64/test_pseries.py | 2 +- tests/functional/ppc64/test_reverse_debug.py | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/functional/ppc/test_74xx.py b/tests/functional/ppc/test_74xx.py index 5386016f26..219c7991ac 100755 --- a/tests/functional/ppc/test_74xx.py +++ b/tests/functional/ppc/test_74xx.py @@ -10,7 +10,7 @@ from qemu_test import QemuSystemTest from qemu_test import wait_for_console_pattern -class ppc74xxCpu(QemuSystemTest): +class Ppc74xxCpu(QemuSystemTest): timeout = 5 diff --git a/tests/functional/ppc/test_sam460ex.py b/tests/functional/ppc/test_sam460ex.py index 31cf9dd6de..024406d155 100755 --- a/tests/functional/ppc/test_sam460ex.py +++ b/tests/functional/ppc/test_sam460ex.py @@ -8,10 +8,11 @@ from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern -class sam460exTest(LinuxKernelTest): +class Sam460exTest(LinuxKernelTest): ASSET_BR2_SAM460EX_LINUX = Asset( - 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc_sam460ex-2023.11-8-gdcd9f0f6eb-20240105/vmlinux', + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main' + '/buildroot/qemu_ppc_sam460ex-2023.11-8-gdcd9f0f6eb-20240105/vmlinux'), '6f46346f3e20e8b5fc050ff363f350f8b9d76a051b9e0bd7ea470cc680c14df2') def test_ppc_sam460ex_buildroot(self): diff --git a/tests/functional/ppc64/test_powernv.py b/tests/functional/ppc64/test_powernv.py index 9ada832b78..0ea6c93e42 100755 --- a/tests/functional/ppc64/test_powernv.py +++ b/tests/functional/ppc64/test_powernv.py @@ -10,7 +10,7 @@ from qemu_test import LinuxKernelTest, Asset from qemu_test import wait_for_console_pattern -class powernvMachine(LinuxKernelTest): +class PowernvMachine(LinuxKernelTest): timeout = 90 KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 ' diff --git a/tests/functional/ppc64/test_pseries.py b/tests/functional/ppc64/test_pseries.py index 67057934e8..7840c4e3ff 100755 --- a/tests/functional/ppc64/test_pseries.py +++ b/tests/functional/ppc64/test_pseries.py @@ -10,7 +10,7 @@ from qemu_test import QemuSystemTest, Asset from qemu_test import wait_for_console_pattern -class pseriesMachine(QemuSystemTest): +class PseriesMachine(QemuSystemTest): timeout = 90 KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 ' diff --git a/tests/functional/ppc64/test_reverse_debug.py b/tests/functional/ppc64/test_reverse_debug.py index 69551fb84d..4eef779936 100755 --- a/tests/functional/ppc64/test_reverse_debug.py +++ b/tests/functional/ppc64/test_reverse_debug.py @@ -18,7 +18,7 @@ from qemu_test import skipFlakyTest from reverse_debugging import ReverseDebugging -class ReverseDebugging_ppc64(ReverseDebugging): +class ReverseDebuggingPpc64(ReverseDebugging): @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992") def test_ppc64_pseries(self): From 693bfeb8b2637782a2a5e3cab240765d9e5eced7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 28 Oct 2025 18:26:50 +0000 Subject: [PATCH 16/22] tests/functional: include logger name and function in messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we collect debug logs from a wide range of code it becomes increasingly confusing to understand where each log messages comes from. Adding "%(name)s" gives us the logger name, which is usually based on the python __name__ symbol, aka the code module name. Then "%(funcName)s" completes the story by identifying the function. Signed-off-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Message-ID: <20251028182651.873256-2-berrange@redhat.com> Signed-off-by: Thomas Huth --- tests/functional/qemu_test/testcase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index a122acb560..d9d114e63e 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -217,7 +217,7 @@ class QemuBaseTest(unittest.TestCase): self._log_fh = logging.FileHandler(self.log_filename, mode='w') self._log_fh.setLevel(logging.DEBUG) fileFormatter = logging.Formatter( - '%(asctime)s - %(levelname)s: %(message)s') + '%(asctime)s - %(levelname)s: %(name)s.%(funcName)s %(message)s') self._log_fh.setFormatter(fileFormatter) self.log.addHandler(self._log_fh) From 0271d73b85d66b6b2990b00e0b55a058d5636e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 28 Oct 2025 18:26:51 +0000 Subject: [PATCH 17/22] tests/functional: include the lower level QMP log messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We've seen a GitLab CI timeout failure in the test_pseries.py test, where it appears likely that the test has hung in a self.qmp('quit') call, but we don't have conclusive proof. Adding the QMP log category to what we capture should help us diagnose this, at the cost of the base.log file becoming significantly more verbose. The previous commit to include the logger category name and function should at least help understanding the more verbose logs. Signed-off-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Message-ID: <20251028182651.873256-3-berrange@redhat.com> Signed-off-by: Thomas Huth --- tests/functional/qemu_test/testcase.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index d9d114e63e..1d773dd697 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -225,6 +225,9 @@ class QemuBaseTest(unittest.TestCase): self.machinelog = logging.getLogger('qemu.machine') self.machinelog.setLevel(logging.DEBUG) self.machinelog.addHandler(self._log_fh) + self.qmplog = logging.getLogger('qemu.qmp') + self.qmplog.setLevel(logging.DEBUG) + self.qmplog.addHandler(self._log_fh) if not self.assets_available(): self.skipTest('One or more assets is not available') @@ -235,6 +238,7 @@ class QemuBaseTest(unittest.TestCase): if self.socketdir is not None: self.socketdir.cleanup() self.socketdir = None + self.qmplog.removeHandler(self._log_fh) self.machinelog.removeHandler(self._log_fh) self.log.removeHandler(self._log_fh) self._log_fh.close() From 0281105bc4c3bff5764b1caa18ee95c14798bccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 28 Oct 2025 19:12:43 +0100 Subject: [PATCH 18/22] hw/s390x: Use memory_region_size() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MemoryRegion::size is private data of MemoryRegion, use the proper memory_region_size() getter to get it. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20251028181300.41475-10-philmd@linaro.org> Reviewed-by: Thomas Huth Reviewed-by: David Hildenbrand Signed-off-by: Thomas Huth --- hw/s390x/s390-pci-inst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index a3bb5aa221..5841dfc4fe 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -396,7 +396,7 @@ static MemoryRegion *s390_get_subregion(MemoryRegion *mr, uint64_t offset, uint64_t subregion_size; QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) { - subregion_size = int128_get64(subregion->size); + subregion_size = memory_region_size(subregion); if ((offset >= subregion->addr) && (offset + len) <= (subregion->addr + subregion_size)) { mr = subregion; From df7e9243d540ee130f044f975af8de33c45f5299 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 16 Oct 2025 19:58:30 +0200 Subject: [PATCH 19/22] target/s390x: Fix missing interrupts for small CKC values Suppose TOD clock value is 0x1111111111111111 and clock-comparator value is 0, in which case clock-comparator interruption should occur immediately. With the current code, tod2time(env->ckc - td->base.low) ends up being a very large number, so this interruption never happens. Fix by firing the timer immediately if env->ckc < td->base.low. Cc: qemu-stable@nongnu.org Reviewed-by: Thomas Huth Signed-off-by: Ilya Leoshkevich Message-ID: <20251016175954.41153-2-iii@linux.ibm.com> Signed-off-by: Thomas Huth --- target/s390x/tcg/misc_helper.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c index 6d9d601d29..215b5b9d93 100644 --- a/target/s390x/tcg/misc_helper.c +++ b/target/s390x/tcg/misc_helper.c @@ -199,11 +199,15 @@ static void update_ckc_timer(CPUS390XState *env) return; } - /* difference between origins */ - time = env->ckc - td->base.low; + if (env->ckc < td->base.low) { + time = 0; + } else { + /* difference between origins */ + time = env->ckc - td->base.low; - /* nanoseconds */ - time = tod2time(time); + /* nanoseconds */ + time = tod2time(time); + } timer_mod(env->tod_timer, time); } From dacfec5157fb9e2249cf393a143bd545e80a6e31 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 16 Oct 2025 19:58:31 +0200 Subject: [PATCH 20/22] target/s390x: Fix missing clock-comparator interrupts after reset After reset, CKC value is set to 0, so if clock-comparator interrupts are enabled, one should occur very shortly thereafter. Currently the code that loads the respective control register does not set tod_timer, so this does not happen. Fix by adding a tcg_s390_tod_updated() call to LCTL and LCTLG. Cc: qemu-stable@nongnu.org Suggested-by: Thomas Huth Reviewed-by: Thomas Huth Signed-off-by: Ilya Leoshkevich Message-ID: <20251016175954.41153-3-iii@linux.ibm.com> Signed-off-by: Thomas Huth --- target/s390x/tcg/mem_helper.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index f1acb1618f..24675fc818 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -1959,6 +1959,10 @@ void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) if (env->cregs[i] != val && i >= 9 && i <= 11) { PERchanged = true; } + if (i == 0 && !(env->cregs[i] & CR0_CKC_SC) && (val & CR0_CKC_SC)) { + BQL_LOCK_GUARD(); + tcg_s390_tod_updated(env_cpu(env), RUN_ON_CPU_NULL); + } env->cregs[i] = val; HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", i, src, val); @@ -1989,10 +1993,15 @@ void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) for (i = r1;; i = (i + 1) % 16) { uint32_t val = cpu_ldl_data_ra(env, src, ra); + uint64_t val64 = deposit64(env->cregs[i], 0, 32, val); if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) { PERchanged = true; } - env->cregs[i] = deposit64(env->cregs[i], 0, 32, val); + if (i == 0 && !(env->cregs[i] & CR0_CKC_SC) && (val64 & CR0_CKC_SC)) { + BQL_LOCK_GUARD(); + tcg_s390_tod_updated(env_cpu(env), RUN_ON_CPU_NULL); + } + env->cregs[i] = val64; HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val); src += sizeof(uint32_t); From fc976a67ded4232cf0b9ae3c11fe051da01e4456 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 16 Oct 2025 19:58:32 +0200 Subject: [PATCH 21/22] target/s390x: Use address generation for register branch targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Indirect branches to addresses taken from registers go through address generation, e.g., for BRANCH ON CONDITION Principles of Operation says: In the RR format, the contents of general register R2 are used to generate the branch address QEMU uses r2_nz handler for the respective register operands. Currently it does not zero out extra bits in 24- and 31-bit addressing modes as required by address generation. The very frequently used s390x_tr_init_disas_context() function has a workaround for this, but the code for saving an old PSW during an interrupt does not. Add the missing masking to r2_nz. Enforce PSW validity by replacing the workaround with an assertion. Reported-by: Thomas Weißschuh Reported-by: Heiko Carstens Link: https://lore.kernel.org/lkml/ab3131a2-c42a-47ff-bf03-e9f68ac053c0@t-8ch.de/ Cc: qemu-stable@nongnu.org Signed-off-by: Ilya Leoshkevich Tested-by: Thomas Weißschuh Message-ID: <20251016175954.41153-4-iii@linux.ibm.com> Signed-off-by: Thomas Huth --- target/s390x/tcg/translate.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index ec9e5a0751..4d2b8c5e2b 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -5613,6 +5613,7 @@ static void in2_r2_nz(DisasContext *s, DisasOps *o) int r2 = get_field(s, r2); if (r2 != 0) { o->in2 = load_reg(r2); + gen_addi_and_wrap_i64(s, o->in2, o->in2, 0); } } #define SPEC_in2_r2_nz 0 @@ -6379,10 +6380,12 @@ static void s390x_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *dc = container_of(dcbase, DisasContext, base); - /* 31-bit mode */ - if (!(dc->base.tb->flags & FLAG_MASK_64)) { - dc->base.pc_first &= 0x7fffffff; - dc->base.pc_next = dc->base.pc_first; + if (dc->base.tb->flags & FLAG_MASK_32) { + if (!(dc->base.tb->flags & FLAG_MASK_64)) { + assert(!(dc->base.pc_first & ~((1ULL << 31) - 1))); + } + } else { + assert(!(dc->base.pc_first & ~((1ULL << 24) - 1))); } dc->cc_op = CC_OP_DYNAMIC; From 0408c61e27aca56c2d40aeb6ca0e5c5f8b8c3845 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 16 Oct 2025 19:58:33 +0200 Subject: [PATCH 22/22] tests/tcg/s390x: Test SET CLOCK COMPARATOR Add a small test to prevent regressions. Cc: qemu-stable@nongnu.org Reviewed-by: Thomas Huth Signed-off-by: Ilya Leoshkevich Message-ID: <20251016175954.41153-5-iii@linux.ibm.com> Signed-off-by: Thomas Huth --- tests/tcg/s390x/Makefile.softmmu-target | 1 + tests/tcg/s390x/sckc.S | 63 +++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/tcg/s390x/sckc.S diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target index 8cd4667c63..a4425d3184 100644 --- a/tests/tcg/s390x/Makefile.softmmu-target +++ b/tests/tcg/s390x/Makefile.softmmu-target @@ -28,6 +28,7 @@ ASM_TESTS = \ mc \ per \ precise-smc-softmmu \ + sckc \ ssm-early \ stosm-early \ stpq \ diff --git a/tests/tcg/s390x/sckc.S b/tests/tcg/s390x/sckc.S new file mode 100644 index 0000000000..ecd64a3059 --- /dev/null +++ b/tests/tcg/s390x/sckc.S @@ -0,0 +1,63 @@ +/* + * Test clock comparator. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + .org 0x130 +ext_old_psw: + .org 0x1b0 +ext_new_psw: + .quad 0x180000000, _ext /* 64-bit mode */ + .org 0x1d0 +pgm_new_psw: + .quad 0x2000000000000,0 /* disabled wait */ + .org 0x200 /* lowcore padding */ + + .globl _start +_start: + lpswe start31_psw +_start31: + stctg %c0,%c0,c0 + oi c0+6,8 /* set clock-comparator subclass mask */ + lctlg %c0,%c0,c0 + +0: + brasl %r14,_f /* %r14's most significant bit is 1 */ + jg 0b +_f: + br %r14 /* it must not end up in ext_old_psw */ + +_ext: + stg %r0,ext_saved_r0 + + lg %r0,ext_counter + aghi %r0,1 + stg %r0,ext_counter + + cgfi %r0,0x1000 + jnz 0f + lpswe success_psw +0: + + stck clock + lg %r0,clock + agfi %r0,0x40000 /* 64us * 0x1000 =~ 0.25s */ + stg %r0,clock + sckc clock + + lg %r0,ext_saved_r0 + lpswe ext_old_psw + + .align 8 +start31_psw: + .quad 0x100000080000000,_start31 /* EX, 31-bit mode */ +success_psw: + .quad 0x2000000000000,0xfff /* see is_special_wait_psw() */ +c0: + .skip 8 +clock: + .quad 0 +ext_counter: + .quad 0 +ext_saved_r0: + .skip 8