[PATCH v2 20/31] tests/functional: let cpio_extract accept filenames
Currently cpio_extract differs from tar_extract/zip_extract in that it only allows a file-like object as input. Adapt it to also support filenames. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/archive.py | 16 +++- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/functional/qemu_test/archive.py b/tests/functional/qemu_test/archive.py index a6fc97a557..bc448dee4a 100644 --- a/tests/functional/qemu_test/archive.py +++ b/tests/functional/qemu_test/archive.py @@ -8,7 +8,7 @@ # Thomas Huth import os -import subprocess +from subprocess import check_call, run, DEVNULL import tarfile import zipfile @@ -25,12 +25,18 @@ def tar_extract(archive, dest_dir, member=None): else: tf.extractall(path=dest_dir) -def cpio_extract(cpio_handle, output_path): +def cpio_extract(archive, output_path): cwd = os.getcwd() os.chdir(output_path) -subprocess.run(['cpio', '-i'], - input=cpio_handle.read(), - stderr=subprocess.DEVNULL) +# Not passing 'check=True' as cpio exits with non-zero +# status if the archive contains any device nodes :-( +if type(archive) == str: +run(['cpio', '-i', '-F', archive], +stdout=DEVNULL, stderr=DEVNULL) +else: +run(['cpio', '-i'], +input=archive.read(), +stdout=DEVNULL, stderr=DEVNULL) os.chdir(cwd) def zip_extract(archive, dest_dir, member=None): -- 2.46.0
[PATCH v2 19/31] tests/functional: add common deb_extract helper
This mirrors the existing archive_extract, cpio_extract and zip_extract helpers Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/archive.py | 13 + tests/functional/qemu_test/linuxkernel.py | 13 - 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tests/functional/qemu_test/archive.py b/tests/functional/qemu_test/archive.py index 06b66701c0..a6fc97a557 100644 --- a/tests/functional/qemu_test/archive.py +++ b/tests/functional/qemu_test/archive.py @@ -12,6 +12,8 @@ import tarfile import zipfile +from .cmd import run_cmd + def tar_extract(archive, dest_dir, member=None): with tarfile.open(archive) as tf: @@ -37,3 +39,14 @@ def zip_extract(archive, dest_dir, member=None): zf.extract(member=member, path=dest_dir) else: zf.extractall(path=dest_dir) + +def deb_extract(archive, dest_dir, member=None): +cwd = os.getcwd() +os.chdir(dest_dir) +try: +(stdout, stderr, ret) = run_cmd(['ar', 't', archive]) +file_path = stdout.split()[2] +run_cmd(['ar', 'x', archive, file_path]) +tar_extract(file_path, dest_dir, member) +finally: +os.chdir(cwd) diff --git a/tests/functional/qemu_test/linuxkernel.py b/tests/functional/qemu_test/linuxkernel.py index 2e4f4e35fd..8f2810f3af 100644 --- a/tests/functional/qemu_test/linuxkernel.py +++ b/tests/functional/qemu_test/linuxkernel.py @@ -6,8 +6,9 @@ import os from .testcase import QemuSystemTest -from .cmd import run_cmd, wait_for_console_pattern -from .utils import archive_extract +from .cmd import wait_for_console_pattern +from .archive import deb_extract + class LinuxKernelTest(QemuSystemTest): KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' @@ -37,13 +38,7 @@ def extract_from_deb(self, deb_path, path): :param path: path within the deb archive of the file to be extracted :returns: path of the extracted file """ -cwd = os.getcwd() -os.chdir(self.workdir) -(stdout, stderr, ret) = run_cmd(['ar', 't', deb_path]) -file_path = stdout.split()[2] -run_cmd(['ar', 'x', deb_path, file_path]) -archive_extract(file_path, self.workdir) -os.chdir(cwd) +deb_extract(deb_path, self.workdir, member="." + path) # Return complete path to extracted file. Because callers to # extract_from_deb() specify 'path' with a leading slash, it is # necessary to use os.path.relpath() as otherwise scratch_file() -- 2.46.0
[PATCH v2 13/31] tests/functional: switch over to using self.scratch_file()
Replace any instances of os.path.join(self.workdir, ".../...") self.workdir + "/.../..." with self.scratch_file("...", "...") which is more compact and portable Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/linuxkernel.py | 7 ++- tests/functional/qemu_test/tuxruntest.py | 2 +- tests/functional/test_aarch64_aspeed.py | 17 --- tests/functional/test_aarch64_raspi3.py | 3 +- tests/functional/test_aarch64_raspi4.py | 4 +- tests/functional/test_aarch64_sbsaref.py | 6 +-- tests/functional/test_aarch64_virt.py | 3 +- tests/functional/test_acpi_bits.py| 49 +-- tests/functional/test_alpha_clipper.py| 4 +- tests/functional/test_arm_aspeed.py | 16 +++--- tests/functional/test_arm_bflt.py | 3 +- tests/functional/test_arm_bpim2u.py | 6 +-- tests/functional/test_arm_canona1100.py | 3 +- tests/functional/test_arm_cubieboard.py | 6 +-- tests/functional/test_arm_emcraft_sf2.py | 2 +- tests/functional/test_arm_integratorcp.py | 3 +- tests/functional/test_arm_orangepi.py | 8 +-- tests/functional/test_arm_raspi2.py | 4 +- tests/functional/test_arm_smdkc210.py | 2 +- tests/functional/test_arm_vexpress.py | 5 +- tests/functional/test_m68k_mcf5208evb.py | 3 +- tests/functional/test_m68k_nextcube.py| 5 +- .../functional/test_microblaze_s3adsp1800.py | 3 +- .../test_microblazeel_s3adsp1800.py | 5 +- tests/functional/test_mips64el_malta.py | 6 +-- tests/functional/test_mips_malta.py | 4 +- tests/functional/test_mipsel_malta.py | 6 +-- tests/functional/test_or1k_sim.py | 2 +- tests/functional/test_ppc64_e500.py | 2 +- tests/functional/test_ppc64_hv.py | 12 + tests/functional/test_ppc_amiga.py| 12 +++-- tests/functional/test_ppc_bamboo.py | 10 ++-- tests/functional/test_ppc_mac.py | 2 +- tests/functional/test_ppc_mpc8544ds.py| 2 +- tests/functional/test_ppc_virtex_ml507.py | 5 +- tests/functional/test_rx_gdbsim.py| 5 +- tests/functional/test_s390x_ccw_virtio.py | 2 +- tests/functional/test_s390x_topology.py | 4 +- tests/functional/test_sh4_r2d.py | 3 +- tests/functional/test_sh4eb_r2d.py| 8 +-- tests/functional/test_sparc64_sun4u.py| 5 +- tests/functional/test_sparc_sun4m.py | 2 +- tests/functional/test_xtensa_lx60.py | 3 +- 43 files changed, 123 insertions(+), 141 deletions(-) diff --git a/tests/functional/qemu_test/linuxkernel.py b/tests/functional/qemu_test/linuxkernel.py index 2b5b9a5fda..2e4f4e35fd 100644 --- a/tests/functional/qemu_test/linuxkernel.py +++ b/tests/functional/qemu_test/linuxkernel.py @@ -46,8 +46,7 @@ def extract_from_deb(self, deb_path, path): os.chdir(cwd) # Return complete path to extracted file. Because callers to # extract_from_deb() specify 'path' with a leading slash, it is -# necessary to use os.path.relpath() as otherwise os.path.join() -# interprets it as an absolute path and drops the self.workdir part. -return os.path.normpath(os.path.join(self.workdir, - os.path.relpath(path, '/'))) +# necessary to use os.path.relpath() as otherwise scratch_file() +# interprets it as an absolute path and drops the required prefix +return os.path.normpath(self.scratch_file(os.path.relpath(path, '/'))) diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py index 2e5c6d110c..0b1bb8f0ed 100644 --- a/tests/functional/qemu_test/tuxruntest.py +++ b/tests/functional/qemu_test/tuxruntest.py @@ -74,7 +74,7 @@ def fetch_tuxrun_assets(self, kernel_asset, rootfs_asset, dtb_asset=None): kernel_image = kernel_asset.fetch() disk_image_zst = rootfs_asset.fetch() -disk_image = self.workdir + "/rootfs.ext4" +disk_image = self.scratch_file("rootfs.ext4") run_cmd(['zstd', "-f", "-d", disk_image_zst, "-o", disk_image]) diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed.py index e196f88537..8ba2c67248 100644 --- a/tests/functional/test_aarch64_aspeed.py +++ b/tests/functional/test_aarch64_aspeed.py @@ -38,26 +38,28 @@ def test_aarch64_ast2700_evb_sdk_v09_02(self): archive_extract(image_path, self.workdir) num_cpu = 4 -image_dir = self.workdir + '/ast2700-default/' -uboot_size = os.path.getsize(image_dir + 'u-boot-nodtb.bin') +uboot_size = os.path.getsize(self.scratch_file('ast2700-default', + 'u-boot-nodtb.bin')) uboot_dtb_load_addr = hex(0x4 + uboot_size) load_images_li
[PATCH v2 06/31] tests/functional: introduce some helpful decorators
Reduce repeated boilerplate with some helper decorators: @skipIfNotPlatform("x86_64", "aarch64") => Skip unless the build host platform matches @skipIfMissingCommands("mkisofs", "losetup") => Skips unless all listed commands are found in $PATH @skipIfMissingImports("numpy", "cv2") => Skips unless all listed modules can be imported @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN";) => Skips unless env var requests flaky tests with the reason documented in the referenced gitlab bug @skipBigData => Skips unless env var permits tests creating big data files @skipUntrustedTest => Skips unless env var permits tests which are potentially dangerous to the host Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/__init__.py | 3 + tests/functional/qemu_test/decorators.py | 107 +++ 2 files changed, 110 insertions(+) create mode 100644 tests/functional/qemu_test/decorators.py diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py index 8fbe67..7dee3522f2 100644 --- a/tests/functional/qemu_test/__init__.py +++ b/tests/functional/qemu_test/__init__.py @@ -13,3 +13,6 @@ exec_command, exec_command_and_wait_for_pattern, get_qemu_img, which from .testcase import QemuBaseTest, QemuUserTest, QemuSystemTest from .linuxkernel import LinuxKernelTest +from .decorators import skipIfMissingCommands, skipIfNotMachine, \ +skipFlakyTest, skipUntrustedTest, skipBigDataTest, \ +skipIfMissingImports diff --git a/tests/functional/qemu_test/decorators.py b/tests/functional/qemu_test/decorators.py new file mode 100644 index 00..df088bc090 --- /dev/null +++ b/tests/functional/qemu_test/decorators.py @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Decorators useful in functional tests + +import os +import platform +from unittest import skipUnless + +from .cmd import which + +''' +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): +def has_cmds(cmdlist): +for cmd in cmdlist: +if not which(cmd): +return False +return True + +return skipUnless(lambda: has_cmds(args), + 'required command(s) "%s" not installed' % + ", ".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): +return skipUnless(lambda: 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): +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(): +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(): +return skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), + 'Test requires large host storage space') + +''' +Decorator to skip execution of a test if the list +of python imports is not available. +Example: + + @skipIfMissingImports("numpy", "cv2") +''' +def skipIfMissingImports(*args): +def has_imports(importlist): +for impname in importlist: +try: +import impname +except ImportError: +return False +return True + +return skipUnless(lambda: has_imports(args), + 'required import(s) "%s" not installed' % + ", ".join(args)) -- 2.46.0
[PATCH v3 40/69] target/arm: Convert CNT, NOT, RBIT (vector) to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 34 ++ target/arm/tcg/a64.decode | 4 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 3e0c061b3c..aff1984a22 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8915,6 +8915,9 @@ static bool do_gvec_fn2(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) TRANS(ABS_v, do_gvec_fn2, a, tcg_gen_gvec_abs) TRANS(NEG_v, do_gvec_fn2, a, tcg_gen_gvec_neg) +TRANS(NOT_v, do_gvec_fn2, a, tcg_gen_gvec_not) +TRANS(CNT_v, do_gvec_fn2, a, gen_gvec_cnt) +TRANS(RBIT_v, do_gvec_fn2, a, gen_gvec_rbit) static bool do_gvec_fn2_bhs(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) { @@ -9229,12 +9232,6 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, TCGCond cond; switch (opcode) { -case 0x5: /* NOT */ -/* This opcode is shared with CNT and RBIT but we have earlier - * enforced that size == 3 if and only if this is the NOT insn. - */ -tcg_gen_not_i64(tcg_rd, tcg_rn); -break; case 0xa: /* CMLT */ cond = TCG_COND_LT; do_cmop: @@ -9291,6 +9288,7 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, break; default: case 0x4: /* CLS, CLZ */ +case 0x5: /* NOT */ case 0x7: /* SQABS, SQNEG */ case 0xb: /* ABS, NEG */ g_assert_not_reached(); @@ -10072,19 +10070,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) case 0x1: /* REV16 */ handle_rev(s, opcode, u, is_q, size, rn, rd); return; -case 0x5: /* CNT, NOT, RBIT */ -if (u && size == 0) { -/* NOT */ -break; -} else if (u && size == 1) { -/* RBIT */ -break; -} else if (!u && size == 0) { -/* CNT */ -break; -} -unallocated_encoding(s); -return; case 0x12: /* XTN, XTN2, SQXTUN, SQXTUN2 */ case 0x14: /* SQXTN, SQXTN2, UQXTN, UQXTN2 */ if (size == 3) { @@ -10302,6 +10287,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) default: case 0x3: /* SUQADD, USQADD */ case 0x4: /* CLS, CLZ */ +case 0x5: /* CNT, NOT, RBIT */ case 0x7: /* SQABS, SQNEG */ case 0xb: /* ABS, NEG */ unallocated_encoding(s); @@ -10324,15 +10310,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) } switch (opcode) { -case 0x5: /* CNT, NOT, RBIT */ -if (!u) { -gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cnt, 0); -} else if (size) { -gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_rbit, 0); -} else { -gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_not, 0); -} -return; case 0x8: /* CMGT, CMGE */ if (u) { gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cge0, size); @@ -10351,6 +10328,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_clt0, size); return; case 0x4: /* CLZ, CLS */ +case 0x5: /* CNT, NOT, RBIT */ case 0xb: g_assert_not_reached(); } diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index 32355ee633..bac81eec7e 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -71,6 +71,7 @@ @rrr_q1e3 ... rm:5 .. rn:5 rd:5 &qrrr_e q=1 esz=3 @_q1e3 ... rm:5 . ra:5 rn:5 rd:5 &q_e q=1 esz=3 +@qrr_b . q:1 .. .. .. .. rn:5 rd:5 &qrr_e esz=0 @qrr_h . q:1 .. .. .. .. rn:5 rd:5 &qrr_e esz=1 @qrr_e . q:1 .. esz:2 .. .. rn:5 rd:5 &qrr_e @@ -1643,3 +1644,6 @@ ABS_v 0.00 1110 ..1 0 10111 0 . . @qrr_e NEG_v 0.10 1110 ..1 0 10111 0 . . @qrr_e CLS_v 0.00 1110 ..1 0 01001 0 . . @qrr_e CLZ_v 0.10 1110 ..1 0 01001 0 . . @qrr_e +CNT_v 0.00 1110 001 0 01011 0 . . @qrr_b +NOT_v 0.10 1110 001 0 01011 0 . . @qrr_b +RBIT_v 0.10 1110 011 0 01011 0 . . @qrr_b -- 2.43.0
[PATCH v2 02/31] tests/functional: resolve str(Asset) to cache file path
Allow an Asset object to be used in place of a filename but making its string representation resolve to the cache file path. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/asset.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py index 559af0351f..c5d3e73c4b 100644 --- a/tests/functional/qemu_test/asset.py +++ b/tests/functional/qemu_test/asset.py @@ -39,6 +39,9 @@ def __repr__(self): return "Asset: url=%s hash=%s cache=%s" % ( self.url, self.hash, self.cache_file) +def __str__(self): +return str(self.cache_file) + def _check(self, cache_file): if self.hash is None: return True -- 2.46.0
[PATCH v2 31/31] tests/functional: ignore errors when caching assets, except for 404
We see periodic errors caching assets due to a combination of transient networking and server problems. With the previous patch to skip running a test when it has missing assets, we can now treat most cache download errors as non-fatal. Only HTTP 404 is retained as fatal, since it is a strong indicator of a fully broken test rather than a transient error. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/asset.py | 14 +- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py index 39832b2587..f0730695f0 100644 --- a/tests/functional/qemu_test/asset.py +++ b/tests/functional/qemu_test/asset.py @@ -15,6 +15,7 @@ from time import sleep from pathlib import Path from shutil import copyfileobj +from urllib.error import HTTPError # Instances of this class must be declared as class level variables @@ -170,7 +171,18 @@ def precache_test(test): for name, asset in vars(test.__class__).items(): if name.startswith("ASSET_") and type(asset) == Asset: log.info("Attempting to cache '%s'" % asset) -asset.fetch() +try: +asset.fetch() +except HTTPError as e: +# Treat 404 as fatal, since it is highly likely to +# indicate a broken test rather than a transient +# server or networking problem +if e.code == 404: +raise + +log.debug(f"HTTP error {e.code} from {asset.url} " + + "skipping asset precache") + log.removeHandler(handler) def precache_suite(suite): -- 2.46.0
[PATCH v2 12/31] tests/functional: switch over to using self.data_file(...)
This removes direct path manipulation to figure out the source dir Reviewed-by: Thomas Huth Signed-off-by: Daniel P. Berrangé --- tests/functional/test_acpi_bits.py | 22 +++--- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/tests/functional/test_acpi_bits.py b/tests/functional/test_acpi_bits.py index 8763ea0822..59d0383563 100755 --- a/tests/functional/test_acpi_bits.py +++ b/tests/functional/test_acpi_bits.py @@ -38,7 +38,6 @@ import tarfile import zipfile -from pathlib import Path from typing import ( List, Optional, @@ -119,7 +118,6 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._vm = None -self._baseDir = None self._debugcon_addr = '0x403' self._debugcon_log = 'debugcon-log.txt' @@ -134,26 +132,22 @@ def _print_log(self, log): def copy_bits_config(self): """ copies the bios bits config file into bits. """ -config_file = 'bits-cfg.txt' -bits_config_dir = os.path.join(self._baseDir, 'acpi-bits', - 'bits-config') +bits_config_file = self.data_file('acpi-bits', + 'bits-config', + 'bits-cfg.txt') target_config_dir = os.path.join(self.workdir, 'bits-%d' %self.BITS_INTERNAL_VER, 'boot') -self.assertTrue(os.path.exists(bits_config_dir)) +self.assertTrue(os.path.exists(bits_config_file)) self.assertTrue(os.path.exists(target_config_dir)) -self.assertTrue(os.access(os.path.join(bits_config_dir, - config_file), os.R_OK)) -shutil.copy2(os.path.join(bits_config_dir, config_file), - target_config_dir) +shutil.copy2(bits_config_file, target_config_dir) self.logger.info('copied config file %s to %s', - config_file, target_config_dir) + bits_config_file, target_config_dir) def copy_test_scripts(self): """copies the python test scripts into bits. """ -bits_test_dir = os.path.join(self._baseDir, 'acpi-bits', - 'bits-tests') +bits_test_dir = self.data_file('acpi-bits', 'bits-tests') target_test_dir = os.path.join(self.workdir, 'bits-%d' %self.BITS_INTERNAL_VER, 'boot', 'python') @@ -256,8 +250,6 @@ def setUp(self): # pylint: disable=arguments-differ super().setUp() self.logger = self.log -self._baseDir = Path(__file__).parent - prebuiltDir = os.path.join(self.workdir, 'prebuilt') if not os.path.isdir(prebuiltDir): os.mkdir(prebuiltDir, mode=0o775) -- 2.46.0
[PATCH v3 23/69] target/arm: Fix decode of fp16 vector fabs, fneg, fsqrt
These opcodes are only supported as vector operations, not as advsimd scalar. Set only_in_vector, and remove the unreachable implementation of scalar fneg. Reported-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index a99f3d0d13..3c1784593a 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -10816,10 +10816,13 @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) break; case 0x2f: /* FABS */ case 0x6f: /* FNEG */ +only_in_vector = true; need_fpst = false; break; case 0x7d: /* FRSQRTE */ +break; case 0x7f: /* FSQRT (vector) */ +only_in_vector = true; break; default: unallocated_encoding(s); @@ -10877,9 +10880,6 @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) case 0x7b: /* FCVTZU */ gen_helper_advsimd_f16touinth(tcg_res, tcg_op, tcg_fpstatus); break; -case 0x6f: /* FNEG */ -tcg_gen_xori_i32(tcg_res, tcg_op, 0x8000); -break; case 0x7d: /* FRSQRTE */ gen_helper_rsqrte_f16(tcg_res, tcg_op, tcg_fpstatus); break; -- 2.43.0
[PATCH v2 30/31] tests/functional: skip tests if assets are not available
If downloading of assets has been disabled, then skip running a test if the assets it has registered are not already downloaded. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/asset.py| 8 +++- tests/functional/qemu_test/testcase.py | 11 +++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py index c5d3e73c4b..39832b2587 100644 --- a/tests/functional/qemu_test/asset.py +++ b/tests/functional/qemu_test/asset.py @@ -65,6 +65,12 @@ def _check(self, cache_file): def valid(self): return self.cache_file.exists() and self._check(self.cache_file) +def fetchable(self): +return not os.environ.get("QEMU_TEST_NO_DOWNLOAD", False) + +def available(self): +return self.valid() or self.fetchable() + def _wait_for_other_download(self, tmp_cache_file): # Another thread already seems to download the asset, so wait until # it is done, while also checking the size to see whether it is stuck @@ -103,7 +109,7 @@ def fetch(self): self.cache_file, self.url) return str(self.cache_file) -if os.environ.get("QEMU_TEST_NO_DOWNLOAD", False): +if not self.fetchable(): raise Exception("Asset cache is invalid and downloads disabled") self.log.info("Downloading %s to %s...", self.url, self.cache_file) diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 7bece8738a..6c67a9459c 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -184,6 +184,14 @@ def scratch_file(self, *args): def log_file(self, *args): return str(Path(self.outputdir, *args)) +def assets_available(self): +for name, asset in vars(self.__class__).items(): +if name.startswith("ASSET_") and type(asset) == Asset: +if not asset.available(): +self.log.debug(f"Asset {asset.url} not available") +return False +return True + def setUp(self, bin_prefix): self.assertIsNotNone(self.qemu_bin, 'QEMU_TEST_QEMU_BINARY must be set') self.arch = self.qemu_bin.split('-')[-1] @@ -209,6 +217,9 @@ def setUp(self, bin_prefix): self.machinelog.setLevel(logging.DEBUG) self.machinelog.addHandler(self._log_fh) +if not self.assets_available(): +self.skipTest('One or more assets is not available') + def tearDown(self): if "QEMU_TEST_KEEP_SCRATCH" not in os.environ: shutil.rmtree(self.workdir) -- 2.46.0
[PATCH v2 21/31] tests/functional: add a generalized archive_extract
There are many types of archives that the tests deal with. Provide a generalized 'archive_extract' that can detect the format and delegate to the appropriate helper for extraction. This ensures that all archive extraction code follows the same design pattern. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/__init__.py | 1 + tests/functional/qemu_test/archive.py | 58 ++ 2 files changed, 59 insertions(+) diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py index fe6cbe3a8a..665c482d13 100644 --- a/tests/functional/qemu_test/__init__.py +++ b/tests/functional/qemu_test/__init__.py @@ -16,3 +16,4 @@ from .decorators import skipIfMissingCommands, skipIfNotMachine, \ skipFlakyTest, skipUntrustedTest, skipBigDataTest, \ skipIfMissingImports +from .archive import archive_extract diff --git a/tests/functional/qemu_test/archive.py b/tests/functional/qemu_test/archive.py index bc448dee4a..c439d9413a 100644 --- a/tests/functional/qemu_test/archive.py +++ b/tests/functional/qemu_test/archive.py @@ -10,8 +10,10 @@ import os from subprocess import check_call, run, DEVNULL import tarfile +from urllib.parse import urlparse import zipfile +from .asset import Asset from .cmd import run_cmd @@ -56,3 +58,59 @@ def deb_extract(archive, dest_dir, member=None): tar_extract(file_path, dest_dir, member) finally: os.chdir(cwd) + +''' +@params archive: filename, Asset, or file-like object to extract +@params dest_dir: target directory to extract into +@params member: optional member file to limit extraction to + +Extracts @archive into @dest_dir. All files are extracted +unless @member specifies a limit. + +If @format is None, heuristics will be applied to guess the format +from the filename or Asset URL. @format must be non-None if @archive +is a file-like object. +''' +def archive_extract(archive, dest_dir, format=None, member=None): +if format is None: +format = guess_archive_format(archive) +if type(archive) == Asset: +archive = str(archive) + +if format == "tar": +tar_extract(archive, dest_dir, member) +elif format == "zip": +zip_extract(archive, dest_dir, member) +elif format == "cpio": +if member is not None: +raise Exception("Unable to filter cpio extraction") +cpio_extract(archive, dest_dir) +elif format == "deb": +if type(archive) != str: +raise Exception("Unable to use file-like object with deb archives") +deb_extract(archive, dest_dir, "./" + member) +else: +raise Exception(f"Unknown archive format {format}") + +''' +@params archive: filename, or Asset to guess + +Guess the format of @compressed, raising an exception if +no format can be determined +''' +def guess_archive_format(archive): +if type(archive) == Asset: +archive = urlparse(archive.url).path +elif type(archive) != str: +raise Exception(f"Unable to guess archive format for {archive}") + +if ".tar." in archive or archive.endswith("tgz"): +return "tar" +elif archive.endswith(".zip"): +return "zip" +elif archive.endswith(".cpio"): +return "cpio" +elif archive.endswith(".deb") or archive.endswith(".udeb"): +return "deb" +else: +raise Exception(f"Unknown archive format for {archive}") -- 2.46.0
Re: [PATCH v3 42/69] target/arm: Introduce gen_gvec_rev{16,32,64}
On 12/11/24 11:19, Philippe Mathieu-Daudé wrote: On 11/12/24 17:30, Richard Henderson wrote: Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate.h | 6 +++ target/arm/tcg/gengvec.c | 58 ++ target/arm/tcg/translate-neon.c | 88 +++-- 3 files changed, 81 insertions(+), 71 deletions(-) diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index cb8e1b2586..342ebedafc 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -586,6 +586,12 @@ void gen_gvec_cnt(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t opr_sz, uint32_t max_sz); void gen_gvec_rbit(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_rev16(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_rev32(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_rev64(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz); Remembering https://lore.kernel.org/qemu-devel/20230822124042.54739-1-phi...@linaro.org/, these gvec helpers might be useful for other targets. These may be factored incorrectly for other usage. Here, for rev, N is the size of the container, and vece specifies the size of the element within each container. It's reverse of the usual meaning of vece, but it maps well to the Arm instruction encoding. The only other bswap I can recall with vector operands is s390x VLBR/VSTBR, and similar for Power VSX, which performs the reversal at the same time as a load/store. So in this case the heavy lifting of the bswap gets pushed off to MO_BSWAP. r~
[PATCH v3 06/69] target/arm: Convert PACGA to decodetree
Remove disas_data_proc_2src, as this was the last insn decoded by that function. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 65 ++ target/arm/tcg/a64.decode | 2 ++ 2 files changed, 13 insertions(+), 54 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 00e55d42ff..ca8b644dc7 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -7674,6 +7674,16 @@ static bool trans_GMI(DisasContext *s, arg_rrr *a) return false; } +static bool trans_PACGA(DisasContext *s, arg_rrr *a) +{ +if (dc_isar_feature(aa64_pauth, s)) { +gen_helper_pacga(cpu_reg(s, a->rd), tcg_env, + cpu_reg(s, a->rn), cpu_reg_sp(s, a->rm)); +return true; +} +return false; +} + /* Logical (shifted register) * 31 30 29 28 24 23 22 21 20 16 1510 95 40 * ++-+---+---+---+--++--+--+ @@ -8555,59 +8565,6 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) } -/* Data-processing (2 source) - * 31 30 29 28 21 20 16 1510 95 40 - * ++---+---+-+--++--+--+ - * | sf | 0 | S | 1 1 0 1 0 1 1 0 | Rm | opcode | Rn | Rd | - * ++---+---+-+--++--+--+ - */ -static void disas_data_proc_2src(DisasContext *s, uint32_t insn) -{ -unsigned int sf, rm, opcode, rn, rd, setflag; -sf = extract32(insn, 31, 1); -setflag = extract32(insn, 29, 1); -rm = extract32(insn, 16, 5); -opcode = extract32(insn, 10, 6); -rn = extract32(insn, 5, 5); -rd = extract32(insn, 0, 5); - -if (setflag && opcode != 0) { -unallocated_encoding(s); -return; -} - -switch (opcode) { -case 12: /* PACGA */ -if (sf == 0 || !dc_isar_feature(aa64_pauth, s)) { -goto do_unallocated; -} -gen_helper_pacga(cpu_reg(s, rd), tcg_env, - cpu_reg(s, rn), cpu_reg_sp(s, rm)); -break; -default: -do_unallocated: -case 0: /* SUBP(S) */ -case 2: /* UDIV */ -case 3: /* SDIV */ -case 4: /* IRG */ -case 5: /* GMI */ -case 8: /* LSLV */ -case 9: /* LSRV */ -case 10: /* ASRV */ -case 11: /* RORV */ -case 16: -case 17: -case 18: -case 19: -case 20: -case 21: -case 22: -case 23: /* CRC32 */ -unallocated_encoding(s); -break; -} -} - /* * Data processing - register * 31 30 29 28 2521 20 16 10 0 @@ -8674,7 +8631,7 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) if (op0) {/* (1 source) */ disas_data_proc_1src(s, insn); } else { /* (2 source) */ -disas_data_proc_2src(s, insn); +goto do_unallocated; } break; case 0x8 ... 0xf: /* (3 source) */ diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index f0a5ffb1cd..a23d6a6645 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -682,6 +682,8 @@ SUBPS 1 01 11010110 . 00 . . @rrr IRG 1 00 11010110 . 000100 . . @rrr GMI 1 00 11010110 . 000101 . . @rrr +PACGA 1 00 11010110 . 001100 . . @rrr + # Data Processing (1-source) # Logical (shifted reg) # Add/subtract (shifted reg) -- 2.43.0
[PATCH v2 08/31] tests/functional: drop 'has_cmd' and 'has_cmds' helpers
The 'which' helper is simpler and sufficient for test needs. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/__init__.py | 2 +- tests/functional/qemu_test/cmd.py| 54 ++-- tests/functional/qemu_test/tuxruntest.py | 10 ++--- 3 files changed, 9 insertions(+), 57 deletions(-) diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py index 7dee3522f2..fe6cbe3a8a 100644 --- a/tests/functional/qemu_test/__init__.py +++ b/tests/functional/qemu_test/__init__.py @@ -8,7 +8,7 @@ from .asset import Asset from .config import BUILD_DIR -from .cmd import has_cmd, has_cmds, run_cmd, is_readable_executable_file, \ +from .cmd import run_cmd, is_readable_executable_file, \ interrupt_interactive_console_until_pattern, wait_for_console_pattern, \ exec_command, exec_command_and_wait_for_pattern, get_qemu_img, which from .testcase import QemuBaseTest, QemuUserTest, QemuSystemTest diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index 600e0509db..bebcd46dcf 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -29,52 +29,6 @@ def which(tool): return p return None -def has_cmd(name, args=None): -""" -This function is for use in a @skipUnless decorator, e.g.: - -@skipUnless(*has_cmd('sudo -n', ('sudo', '-n', 'true'))) -def test_something_that_needs_sudo(self): -... -""" - -if args is None: -args = ('which', name) - -try: -_, stderr, exitcode = run_cmd(args) -except Exception as e: -exitcode = -1 -stderr = str(e) - -if exitcode != 0: -cmd_line = ' '.join(args) -err = f'{name} required, but "{cmd_line}" failed: {stderr.strip()}' -return (False, err) -else: -return (True, '') - -def has_cmds(*cmds): -""" -This function is for use in a @skipUnless decorator and -allows checking for the availability of multiple commands, e.g.: - -@skipUnless(*has_cmds(('cmd1', ('cmd1', '--some-parameter')), - 'cmd2', 'cmd3')) -def test_something_that_needs_cmd1_and_cmd2(self): -... -""" - -for cmd in cmds: -if isinstance(cmd, str): -cmd = (cmd,) - -ok, errstr = has_cmd(*cmd) -if not ok: -return (False, errstr) - -return (True, '') - def run_cmd(args): subp = subprocess.Popen(args, stdout=subprocess.PIPE, @@ -254,7 +208,7 @@ def get_qemu_img(test): qemu_img = os.path.join(BUILD_DIR, 'qemu-img') if os.path.exists(qemu_img): return qemu_img -(has_system_qemu_img, errmsg) = has_cmd('qemu-img') -if has_system_qemu_img: -return 'qemu-img' -test.skipTest(errmsg) +qemu_img = which('qemu-img') +if qemu_img is not None: +return qemu_img +test.skipTest(f"qemu-img not found in {BUILD_DIR} or '$PATH'") diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py index d375f2713b..2e5c6d110c 100644 --- a/tests/functional/qemu_test/tuxruntest.py +++ b/tests/functional/qemu_test/tuxruntest.py @@ -15,7 +15,7 @@ from qemu_test import QemuSystemTest from qemu_test import exec_command_and_wait_for_pattern from qemu_test import wait_for_console_pattern -from qemu_test import has_cmd, run_cmd, get_qemu_img +from qemu_test import which, run_cmd, get_qemu_img class TuxRunBaselineTest(QemuSystemTest): @@ -38,10 +38,8 @@ def setUp(self): super().setUp() # We need zstd for all the tuxrun tests -(has_zstd, msg) = has_cmd('zstd') -if has_zstd is False: -self.skipTest(msg) -self.zstd = 'zstd' +if which('zstd') is None: +self.skipTest("zstd not found in $PATH") # Pre-init TuxRun specific settings: Most machines work with # reasonable defaults but we sometimes need to tweak the @@ -78,7 +76,7 @@ def fetch_tuxrun_assets(self, kernel_asset, rootfs_asset, dtb_asset=None): disk_image = self.workdir + "/rootfs.ext4" -run_cmd([self.zstd, "-f", "-d", disk_image_zst, +run_cmd(['zstd', "-f", "-d", disk_image_zst, "-o", disk_image]) # zstd copies source archive permissions for the output # file, so must make this writable for QEMU -- 2.46.0
[PATCH v3 17/69] target/arm: Convert SETF8, SETF16 to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 48 +- target/arm/tcg/a64.decode | 4 +++ 2 files changed, 11 insertions(+), 41 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 1af41e22eb..774689641d 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8077,38 +8077,21 @@ static bool trans_RMIF(DisasContext *s, arg_RMIF *a) return true; } -/* - * Evaluate into flags - * 31 30 292115 1410 5 4 0 - * +--+--+--+-+-++-+--+--+--+ - * |sf|op| S| 1 1 0 1 0 0 0 0 | opcode2 | sz | 0 0 1 0 | Rn |o3| mask | - * +--+--+--+-+-++-+--+--+--+ - */ -static void disas_evaluate_into_flags(DisasContext *s, uint32_t insn) +static bool do_setf(DisasContext *s, int rn, int shift) { -int o3_mask = extract32(insn, 0, 5); -int rn = extract32(insn, 5, 5); -int o2 = extract32(insn, 15, 6); -int sz = extract32(insn, 14, 1); -int sf_op_s = extract32(insn, 29, 3); -TCGv_i32 tmp; -int shift; +TCGv_i32 tmp = tcg_temp_new_i32(); -if (sf_op_s != 1 || o2 != 0 || o3_mask != 0xd || -!dc_isar_feature(aa64_condm_4, s)) { -unallocated_encoding(s); -return; -} -shift = sz ? 16 : 24; /* SETF16 or SETF8 */ - -tmp = tcg_temp_new_i32(); tcg_gen_extrl_i64_i32(tmp, cpu_reg(s, rn)); tcg_gen_shli_i32(cpu_NF, tmp, shift); tcg_gen_shli_i32(cpu_VF, tmp, shift - 1); tcg_gen_mov_i32(cpu_ZF, cpu_NF); tcg_gen_xor_i32(cpu_VF, cpu_VF, cpu_NF); +return true; } +TRANS_FEAT(SETF8, aa64_condm_4, do_setf, a->rn, 24) +TRANS_FEAT(SETF16, aa64_condm_4, do_setf, a->rn, 16) + /* Conditional compare (immediate / register) * 31 30 29 28 27 26 25 24 23 22 21 2016 15 12 11 10 9 5 4 3 0 * +--+--+--+++--++--+--+--+-+ @@ -8277,30 +8260,12 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) { int op1 = extract32(insn, 28, 1); int op2 = extract32(insn, 21, 4); -int op3 = extract32(insn, 10, 6); if (!op1) { goto do_unallocated; } switch (op2) { -case 0x0: -switch (op3) { -case 0x02: /* Evaluate into flags */ -case 0x12: -case 0x22: -case 0x32: -disas_evaluate_into_flags(s, insn); -break; - -default: -case 0x00: /* Add/subtract (with carry) */ -case 0x01: /* Rotate right into flags */ -case 0x21: -goto do_unallocated; -} -break; - case 0x2: /* Conditional compare */ disas_cc(s, insn); /* both imm and reg forms */ break; @@ -8311,6 +8276,7 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) default: do_unallocated: +case 0x0: case 0x6: /* Data-processing */ case 0x8 ... 0xf: /* (3 source) */ unallocated_encoding(s); diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index 454494742e..ae2c6831d7 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -757,6 +757,10 @@ SBCS. 11 1101 . 00 . . @rrr_sf RMIF1 01 1101 imm:6 1 rn:5 0 mask:4 # Evaluate into flags + +SETF8 0 01 1101 0 10 rn:5 01101 +SETF16 0 01 1101 0 010010 rn:5 01101 + # Conditional compare (regster) # Conditional compare (immediate) # Conditional select -- 2.43.0
[PATCH v2 24/31] tests/functional: add a generalized uncompress helper
There are many types of compression that the tests deal with, and it makes sense to have a single helper 'uncompress' that can deal with all. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/__init__.py | 1 + tests/functional/qemu_test/uncompress.py | 47 2 files changed, 48 insertions(+) diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py index 665c482d13..3bd043e608 100644 --- a/tests/functional/qemu_test/__init__.py +++ b/tests/functional/qemu_test/__init__.py @@ -17,3 +17,4 @@ skipFlakyTest, skipUntrustedTest, skipBigDataTest, \ skipIfMissingImports from .archive import archive_extract +from .uncompress import uncompress diff --git a/tests/functional/qemu_test/uncompress.py b/tests/functional/qemu_test/uncompress.py index 955170df65..6d02ded066 100644 --- a/tests/functional/qemu_test/uncompress.py +++ b/tests/functional/qemu_test/uncompress.py @@ -11,6 +11,9 @@ import lzma import os import shutil +from urllib.parse import urlparse + +from .asset import Asset def gzip_uncompress(gz_path, output_path): @@ -34,3 +37,47 @@ def lzma_uncompress(xz_path, output_path): except: os.remove(output_path) raise + +''' +@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): +if format is None: +format = guess_uncompress_format(compressed) + +if format == "xz": +lzma_uncompress(str(compressed), uncompressed) +elif format == "gz": +gzip_uncompress(str(compressed), uncompressed) +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: +compressed = urlparse(compressed.url).path +elif type(compressed) != str: +raise Exception(f"Unable to guess compression cformat for {compressed}") + +(name, ext) = os.path.splitext(compressed) +if ext == ".xz": +return "xz" +elif ext == ".gz": +return "gz" +else: +raise Exception(f"Unknown compression format for {compressed}") -- 2.46.0
[PATCH v2 10/31] tests/functional: switch over to using self.log_file(...)
This removes direct access of the 'self.logdir' variable. Reviewed-by: Thomas Huth Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/testcase.py | 9 - tests/functional/test_virtio_gpu.py| 4 +--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 89425b737c..2174fbb155 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -126,7 +126,7 @@ def scratch_file(self, *args): Returns: string representing a file path ''' def log_file(self, *args): -return str(Path(self.logdir, *args)) +return str(Path(self.outputdir, *args)) def setUp(self, bin_prefix): self.assertIsNotNone(self.qemu_bin, 'QEMU_TEST_QEMU_BINARY must be set') @@ -138,8 +138,7 @@ def setUp(self, bin_prefix): self.workdir = os.path.join(self.outputdir, 'scratch') os.makedirs(self.workdir, exist_ok=True) -self.logdir = self.outputdir -self.log_filename = os.path.join(self.logdir, 'base.log') +self.log_filename = self.log_file('base.log') self.log = logging.getLogger('qemu-test') self.log.setLevel(logging.DEBUG) self._log_fh = logging.FileHandler(self.log_filename, mode='w') @@ -215,7 +214,7 @@ def setUp(self): console_log = logging.getLogger('console') console_log.setLevel(logging.DEBUG) -self.console_log_name = os.path.join(self.logdir, 'console.log') +self.console_log_name = self.log_file('console.log') self._console_log_fh = logging.FileHandler(self.console_log_name, mode='w') self._console_log_fh.setLevel(logging.DEBUG) @@ -269,7 +268,7 @@ def _new_vm(self, name, *args): vm = QEMUMachine(self.qemu_bin, name=name, base_temp_dir=self.workdir, - log_dir=self.logdir) + log_dir=self.log_file()) self.log.debug('QEMUMachine "%s" created', name) self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir) diff --git a/tests/functional/test_virtio_gpu.py b/tests/functional/test_virtio_gpu.py index 2d298b1f02..7654421e6b 100755 --- a/tests/functional/test_virtio_gpu.py +++ b/tests/functional/test_virtio_gpu.py @@ -100,9 +100,7 @@ def test_vhost_user_vga_virgl(self): os.set_inheritable(qemu_sock.fileno(), True) os.set_inheritable(vug_sock.fileno(), True) -self._vug_log_path = os.path.join( -self.logdir, "vhost-user-gpu.log" -) +self._vug_log_path = self.log_file("vhost-user-gpu.log") self._vug_log_file = open(self._vug_log_path, "wb") self.log.info('Complete vhost-user-gpu.log file can be ' 'found at %s', self._vug_log_path) -- 2.46.0
[PATCH v3 36/69] target/arm: Convert ABS, NEG to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 46 +++--- target/arm/tcg/a64.decode | 4 +++ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 9bb9668d11..c697f0e944 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8889,6 +8889,33 @@ static const ENVScalar1 f_scalar_sqneg = { TRANS(SQNEG_s, do_env_scalar1, a, &f_scalar_sqneg) TRANS(SQNEG_v, do_env_vector1, a, &f_scalar_sqneg) +static bool do_scalar1_d(DisasContext *s, arg_rr *a, ArithOneOp *f) +{ +if (fp_access_check(s)) { +TCGv_i64 t = read_fp_dreg(s, a->rn); +f(t, t); +write_fp_dreg(s, a->rd, t); +} +return true; +} + +TRANS(ABS_s, do_scalar1_d, a, tcg_gen_abs_i64) +TRANS(NEG_s, do_scalar1_d, a, tcg_gen_neg_i64) + +static bool do_gvec_fn2(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) +{ +if (!a->q && a->esz == MO_64) { +return false; +} +if (fp_access_check(s)) { +gen_gvec_fn2(s, a->q, a->rd, a->rn, fn, a->esz); +} +return true; +} + +TRANS(ABS_v, do_gvec_fn2, a, tcg_gen_gvec_abs) +TRANS(NEG_v, do_gvec_fn2, a, tcg_gen_gvec_neg) + /* Common vector code for handling integer to FP conversion */ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, int elements, int is_signed, @@ -9213,13 +9240,6 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, case 0x9: /* CMEQ, CMLE */ cond = u ? TCG_COND_LE : TCG_COND_EQ; goto do_cmop; -case 0xb: /* ABS, NEG */ -if (u) { -tcg_gen_neg_i64(tcg_rd, tcg_rn); -} else { -tcg_gen_abs_i64(tcg_rd, tcg_rn); -} -break; case 0x2f: /* FABS */ gen_vfp_absd(tcg_rd, tcg_rn); break; @@ -9264,6 +9284,7 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, break; default: case 0x7: /* SQABS, SQNEG */ +case 0xb: /* ABS, NEG */ g_assert_not_reached(); } } @@ -9614,7 +9635,6 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) /* fall through */ case 0x8: /* CMGT, CMGE */ case 0x9: /* CMEQ, CMLE */ -case 0xb: /* ABS, NEG */ if (size != 3) { unallocated_encoding(s); return; @@ -9705,6 +9725,7 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) default: case 0x3: /* USQADD / SUQADD */ case 0x7: /* SQABS / SQNEG */ +case 0xb: /* ABS, NEG */ unallocated_encoding(s); return; } @@ -10103,7 +10124,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) /* fall through */ case 0x8: /* CMGT, CMGE */ case 0x9: /* CMEQ, CMLE */ -case 0xb: /* ABS, NEG */ if (size == 3 && !is_q) { unallocated_encoding(s); return; @@ -10280,6 +10300,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) default: case 0x3: /* SUQADD, USQADD */ case 0x7: /* SQABS, SQNEG */ +case 0xb: /* ABS, NEG */ unallocated_encoding(s); return; } @@ -10324,12 +10345,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_clt0, size); return; case 0xb: -if (u) { /* ABS, NEG */ -gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_neg, size); -} else { -gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_abs, size); -} -return; +g_assert_not_reached(); } if (size == 3) { diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index 17ecdac9db..f112951df7 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -1632,8 +1632,12 @@ SQRSHRUN_si 0111 0 ... 10001 1 . . @shri_s SQABS_s 0101 1110 ..1 0 0 0 . . @rr_e SQNEG_s 0111 1110 ..1 0 0 0 . . @rr_e +ABS_s 0101 1110 111 0 10111 0 . . @rr +NEG_s 0111 1110 111 0 10111 0 . . @rr # Advanced SIMD two-register miscellaneous SQABS_v 0.00 1110 ..1 0 0 0 . . @qrr_e SQNEG_v 0.10 1110 ..1 0 0 0 . . @qrr_e +ABS_v 0.00 1110 ..1 0 10111 0 . . @qrr_e +NEG_v 0.10 1110 ..1 0 10111 0 . . @qrr_e -- 2.43.0
[PATCH v2 15/31] tests/functional: remove redundant 'rmtree' call
Everything in the scratch directory is automatically purged. Calling 'rmtree' again breaks the ability to optionally preserve the scratch directory contents. Reviewed-by: Thomas Huth Signed-off-by: Daniel P. Berrangé --- tests/functional/test_sh4eb_r2d.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/functional/test_sh4eb_r2d.py b/tests/functional/test_sh4eb_r2d.py index b8dadabf3c..c8954c93eb 100755 --- a/tests/functional/test_sh4eb_r2d.py +++ b/tests/functional/test_sh4eb_r2d.py @@ -4,8 +4,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import shutil - from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern from qemu_test.utils import archive_extract @@ -26,7 +24,6 @@ def test_sh4eb_r2d(self): 'initramfs.cpio.gz'), console_index=1, wait_for='Type exit when done') exec_command_and_wait_for_pattern(self, 'exit', 'Restarting system') -shutil.rmtree(self.scratch_file('sh4eb')) if __name__ == '__main__': LinuxKernelTest.main() -- 2.46.0
[PULL 24/72] target/ppc: Set Float3NaNPropRule explicitly
Set the Float3NaNPropRule explicitly for PPC, and remove the ifdef from pickNaNMulAdd(). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20241202131347.498124-20-peter.mayd...@linaro.org --- target/ppc/cpu_init.c | 8 fpu/softfloat-specialize.c.inc | 6 -- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index f18908a643a..eb9d7b13701 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7270,6 +7270,14 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type) */ set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status); set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status); +/* + * NaN propagation for fused multiply-add: + * if fRA is a NaN return it; otherwise if fRB is a NaN return it; + * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB + * whereas QEMU labels the operands as (a * b) + c. + */ +set_float_3nan_prop_rule(float_3nan_prop_acb, &env->fp_status); +set_float_3nan_prop_rule(float_3nan_prop_acb, &env->vec_status); /* * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer * to return an input NaN if we have one (ie c) rather than generating diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index d610f460026..173b9eadb57 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -511,12 +511,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, } else { rule = float_3nan_prop_s_cab; } -#elif defined(TARGET_PPC) -/* - * If fRA is a NaN return it; otherwise if fRB is a NaN return it; - * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB - */ -rule = float_3nan_prop_acb; #elif defined(TARGET_S390X) rule = float_3nan_prop_s_abc; #elif defined(TARGET_SPARC) -- 2.34.1
[PATCH v2 23/31] tests/functional: convert tests to new archive_extract helper
Replace use of utils.archive_extract and extract_from_deb with the new archive_extract helper. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/linuxkernel.py | 20 +-- tests/functional/test_aarch64_aspeed.py | 5 ++- tests/functional/test_aarch64_raspi3.py | 8 + tests/functional/test_aarch64_raspi4.py | 14 tests/functional/test_acpi_bits.py| 15 ++-- tests/functional/test_arm_aspeed.py | 26 -- tests/functional/test_arm_bflt.py | 3 +- tests/functional/test_arm_bpim2u.py | 26 +++--- tests/functional/test_arm_canona1100.py | 11 +++--- tests/functional/test_arm_cubieboard.py | 20 +-- tests/functional/test_arm_orangepi.py | 35 +-- tests/functional/test_arm_raspi2.py | 14 tests/functional/test_arm_smdkc210.py | 9 +++-- tests/functional/test_arm_vexpress.py | 5 ++- tests/functional/test_m68k_mcf5208evb.py | 5 ++- tests/functional/test_m68k_q800.py| 5 ++- .../functional/test_microblaze_s3adsp1800.py | 5 ++- .../test_microblazeel_s3adsp1800.py | 5 ++- tests/functional/test_mips64el_fuloong2e.py | 6 ++-- tests/functional/test_mips64el_malta.py | 6 ++-- tests/functional/test_mips_malta.py | 12 +++ tests/functional/test_mipsel_malta.py | 5 +-- tests/functional/test_or1k_sim.py | 5 ++- tests/functional/test_ppc64_e500.py | 5 ++- tests/functional/test_ppc_amiga.py| 6 ++-- tests/functional/test_ppc_bamboo.py | 5 ++- tests/functional/test_ppc_mac.py | 6 ++-- tests/functional/test_ppc_mpc8544ds.py| 8 ++--- tests/functional/test_ppc_virtex_ml507.py | 5 ++- tests/functional/test_sh4_r2d.py | 5 ++- tests/functional/test_sh4eb_r2d.py| 5 ++- tests/functional/test_sparc64_sun4u.py| 8 ++--- tests/functional/test_sparc_sun4m.py | 5 ++- tests/functional/test_xtensa_lx60.py | 5 ++- 34 files changed, 127 insertions(+), 201 deletions(-) diff --git a/tests/functional/qemu_test/linuxkernel.py b/tests/functional/qemu_test/linuxkernel.py index 8f2810f3af..155855541f 100644 --- a/tests/functional/qemu_test/linuxkernel.py +++ b/tests/functional/qemu_test/linuxkernel.py @@ -3,11 +3,9 @@ # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. -import os - from .testcase import QemuSystemTest from .cmd import wait_for_console_pattern -from .archive import deb_extract + class LinuxKernelTest(QemuSystemTest): @@ -29,19 +27,3 @@ def launch_kernel(self, kernel, initrd=None, dtb=None, console_index=0, self.vm.launch() if wait_for: self.wait_for_console_pattern(wait_for) - -def extract_from_deb(self, deb_path, path): -""" -Extracts a file from a deb package into the test workdir - -:param deb_path: path to the deb archive -:param path: path within the deb archive of the file to be extracted -:returns: path of the extracted file -""" -deb_extract(deb_path, self.workdir, member="." + path) -# Return complete path to extracted file. Because callers to -# extract_from_deb() specify 'path' with a leading slash, it is -# necessary to use os.path.relpath() as otherwise scratch_file() -# interprets it as an absolute path and drops the required prefix -return os.path.normpath(self.scratch_file(os.path.relpath(path, '/'))) - diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed.py index 8ba2c67248..141d863859 100644 --- a/tests/functional/test_aarch64_aspeed.py +++ b/tests/functional/test_aarch64_aspeed.py @@ -11,7 +11,7 @@ from qemu_test import QemuSystemTest, Asset from qemu_test import wait_for_console_pattern from qemu_test import exec_command_and_wait_for_pattern -from qemu_test.utils import archive_extract + class AST2x00MachineSDK(QemuSystemTest): @@ -34,8 +34,7 @@ def do_test_aarch64_aspeed_sdk_start(self, image): def test_aarch64_ast2700_evb_sdk_v09_02(self): self.set_machine('ast2700-evb') -image_path = self.ASSET_SDK_V902_AST2700.fetch() -archive_extract(image_path, self.workdir) +self.archive_extract(self.ASSET_SDK_V902_AST2700) num_cpu = 4 uboot_size = os.path.getsize(self.scratch_file('ast2700-default', diff --git a/tests/functional/test_aarch64_raspi3.py b/tests/functional/test_aarch64_raspi3.py index 98ed6f9d56..74f6630ed2 100755 --- a/tests/functional/test_aarch64_raspi3.py +++ b/tests/functional/test_aarch64_raspi3.py @@ -7,8 +7,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from zipfile import ZipFile - from qemu_test import LinuxKernelTest, Asset @@ -21,11 +19,7 @@ cl
[PATCH v3 00/69] target/arm: AArch64 decodetree conversion, final part
Finish the conversion of all aarch64 instructions to decodetree. Changes for v3: - Fix decode for f16 fsqrt (vector) in patch 23, prior to conversion. This is the only patch without R-B. r~ Richard Henderson (69): target/arm: Add section labels for "Data Processing (register)" target/arm: Convert UDIV, SDIV to decodetree target/arm: Convert LSLV, LSRV, ASRV, RORV to decodetree target/arm: Convert CRC32, CRC32C to decodetree target/arm: Convert SUBP, IRG, GMI to decodetree target/arm: Convert PACGA to decodetree target/arm: Convert RBIT, REV16, REV32, REV64 to decodetree target/arm: Convert CLZ, CLS to decodetree target/arm: Convert PAC[ID]*, AUT[ID]* to decodetree target/arm: Convert XPAC[ID] to decodetree target/arm: Convert disas_logic_reg to decodetree target/arm: Convert disas_add_sub_ext_reg to decodetree target/arm: Convert disas_add_sub_reg to decodetree target/arm: Convert disas_data_proc_3src to decodetree target/arm: Convert disas_adc_sbc to decodetree target/arm: Convert RMIF to decodetree target/arm: Convert SETF8, SETF16 to decodetree target/arm: Convert CCMP, CCMN to decodetree target/arm: Convert disas_cond_select to decodetree target/arm: Introduce fp_access_check_scalar_hsd target/arm: Introduce fp_access_check_vector_hsd target/arm: Convert FCMP, FCMPE, FCCMP, FCCMPE to decodetree target/arm: Fix decode of fp16 vector fabs, fneg, fsqrt target/arm: Convert FMOV, FABS, FNEG (scalar) to decodetree target/arm: Pass fpstatus to vfp_sqrt* target/arm: Remove helper_sqrt_f16 target/arm: Convert FSQRT (scalar) to decodetree target/arm: Convert FRINT[NPMSAXI] (scalar) to decodetree target/arm: Convert BFCVT to decodetree target/arm: Convert FRINT{32,64}[ZX] (scalar) to decodetree target/arm: Convert FCVT (scalar) to decodetree target/arm: Convert handle_fpfpcvt to decodetree target/arm: Convert FJCVTZS to decodetree target/arm: Convert handle_fmov to decodetree target/arm: Convert SQABS, SQNEG to decodetree target/arm: Convert ABS, NEG to decodetree target/arm: Introduce gen_gvec_cls, gen_gvec_clz target/arm: Convert CLS, CLZ (vector) to decodetree target/arm: Introduce gen_gvec_cnt, gen_gvec_rbit target/arm: Convert CNT, NOT, RBIT (vector) to decodetree target/arm: Convert CMGT, CMGE, GMLT, GMLE, CMEQ (zero) to decodetree target/arm: Introduce gen_gvec_rev{16,32,64} target/arm: Convert handle_rev to decodetree target/arm: Move helper_neon_addlp_{s8,s16} to neon_helper.c target/arm: Introduce gen_gvec_{s,u}{add,ada}lp target/arm: Convert handle_2misc_pairwise to decodetree target/arm: Remove helper_neon_{add,sub}l_u{16,32} target/arm: Introduce clear_vec target/arm: Convert XTN, SQXTUN, SQXTN, UQXTN to decodetree target/arm: Convert FCVTN, BFCVTN to decodetree target/arm: Convert FCVTXN to decodetree target/arm: Convert SHLL to decodetree target/arm: Implement gen_gvec_fabs, gen_gvec_fneg target/arm: Convert FABS, FNEG (vector) to decodetree target/arm: Convert FSQRT (vector) to decodetree target/arm: Convert FRINT* (vector) to decodetree target/arm: Convert FCVT* (vector, integer) scalar to decodetree target/arm: Convert FCVT* (vector, fixed-point) scalar to decodetree target/arm: Convert [US]CVTF (vector, integer) scalar to decodetree target/arm: Convert [US]CVTF (vector, fixed-point) scalar to decodetree target/arm: Rename helper_gvec_vcvt_[hf][su] with _rz target/arm: Convert [US]CVTF (vector) to decodetree target/arm: Convert FCVTZ[SU] (vector, fixed-point) to decodetree target/arm: Convert FCVT* (vector, integer) to decodetree target/arm: Convert handle_2misc_fcmp_zero to decodetree target/arm: Convert FRECPE, FRECPX, FRSQRTE to decodetree target/arm: Introduce gen_gvec_urecpe, gen_gvec_ursqrte target/arm: Convert URECPE and URSQRTE to decodetree target/arm: Convert FCVTL to decodetree target/arm/helper.h | 43 +- target/arm/tcg/helper-a64.h |7 - target/arm/tcg/translate.h | 35 + target/arm/tcg/gengvec.c| 369 ++ target/arm/tcg/helper-a64.c | 104 - target/arm/tcg/neon_helper.c| 106 +- target/arm/tcg/translate-a64.c | 5670 ++- target/arm/tcg/translate-neon.c | 337 +- target/arm/tcg/translate-vfp.c |6 +- target/arm/tcg/vec_helper.c | 65 +- target/arm/vfp_helper.c | 16 +- target/arm/tcg/a64.decode | 502 ++- 12 files changed, 2888 insertions(+), 4372 deletions(-) -- 2.43.0
[PULL 10/49] rust: build: establish a baseline of lints across all crates
Many lints that default to allow can be helpful in detecting bugs or keeping the code style homogeneous. Add them liberally, though perhaps not as liberally as in hw/char/pl011/src/lib.rs. In particular, enabling entire groups can be problematic because of bitrot when new links are added in the future. For Clippy, this is actually a feature that is only present in Cargo 1.74.0 but, since we are not using Cargo to *build* QEMU, only developers will need a new-enough cargo and only to run tools such as clippy. The requirement does not apply to distros that are building QEMU. Reviewed-by: Junjie Mao Signed-off-by: Paolo Bonzini --- rust/Cargo.toml | 68 +++ rust/hw/char/pl011/src/lib.rs | 19 ++ rust/qemu-api/src/bindings.rs | 6 ++-- 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 358c517bc56..6ec19b67297 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -19,3 +19,71 @@ unknown_lints = "allow" # Prohibit code that is forbidden in Rust 2024 unsafe_op_in_unsafe_fn = "deny" + +[workspace.lints.rustdoc] +private_intra_doc_links = "allow" + +broken_intra_doc_links = "deny" +invalid_html_tags = "deny" +invalid_rust_codeblocks = "deny" +bare_urls = "deny" +unescaped_backticks = "deny" +redundant_explicit_links = "deny" + +[workspace.lints.clippy] +# default-warn lints +result_unit_err = "allow" +should_implement_trait = "deny" +# can be for a reason, e.g. in callbacks +unused_self = "allow" + +# default-allow lints +as_underscore = "deny" +assertions_on_result_states = "deny" +bool_to_int_with_if = "deny" +borrow_as_ptr = "deny" +cast_lossless = "deny" +dbg_macro = "deny" +debug_assert_with_mut_call = "deny" +derive_partial_eq_without_eq = "deny" +doc_markdown = "deny" +empty_structs_with_brackets = "deny" +ignored_unit_patterns = "deny" +implicit_clone = "deny" +macro_use_imports = "deny" +missing_const_for_fn = "deny" +missing_safety_doc = "deny" +multiple_crate_versions = "deny" +mut_mut = "deny" +needless_bitwise_bool = "deny" +needless_pass_by_ref_mut = "deny" +no_effect_underscore_binding = "deny" +option_option = "deny" +or_fun_call = "deny" +ptr_as_ptr = "deny" +pub_underscore_fields = "deny" +redundant_clone = "deny" +redundant_closure_for_method_calls = "deny" +redundant_else = "deny" +redundant_pub_crate = "deny" +ref_binding_to_reference = "deny" +ref_option_ref = "deny" +return_self_not_must_use = "deny" +same_name_method = "deny" +semicolon_inside_block = "deny" +shadow_unrelated = "deny" +significant_drop_in_scrutinee = "deny" +significant_drop_tightening = "deny" +suspicious_operation_groupings = "deny" +transmute_ptr_to_ptr = "deny" +transmute_undefined_repr = "deny" +type_repetition_in_bounds = "deny" +used_underscore_binding = "deny" + +# nice to have, but cannot be enabled yet +#wildcard_imports = "deny" # still have many bindings::* imports +#ptr_cast_constness = "deny" # needs 1.65.0 for cast_mut()/cast_const() + +# these may have false positives +#option_if_let_else = "deny" +cognitive_complexity = "deny" diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs index cd0a49acb91..4dc0e8f345f 100644 --- a/rust/hw/char/pl011/src/lib.rs +++ b/rust/hw/char/pl011/src/lib.rs @@ -14,28 +14,15 @@ //! the [`registers`] module for register types. #![deny( -rustdoc::broken_intra_doc_links, -rustdoc::redundant_explicit_links, clippy::correctness, clippy::suspicious, clippy::complexity, clippy::perf, clippy::cargo, clippy::nursery, -clippy::style, -// restriction group -clippy::dbg_macro, -clippy::as_underscore, -clippy::assertions_on_result_states, -// pedantic group -clippy::doc_markdown, -clippy::borrow_as_ptr, -clippy::cast_lossless, -clippy::option_if_let_else, -clippy::missing_const_for_fn, -clippy::cognitive_complexity, -clippy::missing_safety_doc, -)] +clippy::style +)] +#![allow(clippy::upper_case_acronyms)] #![allow(clippy::result_unit_err)] extern crate bilge; diff --git a/rust/qemu-api/src/bindings.rs b/rust/qemu-api/src/bindings.rs index 0b76ec58bee..8a9b821bb91 100644 --- a/rust/qemu-api/src/bindings.rs +++ b/rust/qemu-api/src/bindings.rs @@ -7,10 +7,10 @@ non_snake_case, non_upper_case_globals, unsafe_op_in_unsafe_fn, +clippy::pedantic, +clippy::restriction, +clippy::style, clippy::missing_const_for_fn, -clippy::too_many_arguments, -clippy::approx_constant, -clippy::use_self, clippy::useless_transmute, clippy::missing_safety_doc )] -- 2.47.1
[PATCH v3 67/69] target/arm: Introduce gen_gvec_urecpe, gen_gvec_ursqrte
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/helper.h | 3 +++ target/arm/tcg/translate.h | 5 + target/arm/tcg/gengvec.c| 16 target/arm/tcg/translate-neon.c | 4 ++-- target/arm/tcg/vec_helper.c | 22 ++ 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 1132a5cab6..9919b1367b 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -1121,6 +1121,9 @@ DEF_HELPER_FLAGS_4(gvec_uminp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_uminp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_uminp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_urecpe_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ursqrte_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + #ifdef TARGET_AARCH64 #include "tcg/helper-a64.h" #include "tcg/helper-sve.h" diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index b996de2c15..9b9abf1992 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -608,6 +608,11 @@ void gen_gvec_fabs(unsigned vece, uint32_t dofs, uint32_t aofs, void gen_gvec_fneg(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t oprsz, uint32_t maxsz); +void gen_gvec_urecpe(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_ursqrte(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz); + /* * Forward to the isar_feature_* tests given a DisasContext pointer. */ diff --git a/target/arm/tcg/gengvec.c b/target/arm/tcg/gengvec.c index 01c9d5436d..01867f8ace 100644 --- a/target/arm/tcg/gengvec.c +++ b/target/arm/tcg/gengvec.c @@ -2711,3 +2711,19 @@ void gen_gvec_fneg(unsigned vece, uint32_t dofs, uint32_t aofs, uint64_t s_bit = 1ull << ((8 << vece) - 1); tcg_gen_gvec_xori(vece, dofs, aofs, s_bit, oprsz, maxsz); } + +void gen_gvec_urecpe(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz) +{ +assert(vece == MO_32); +tcg_gen_gvec_2_ool(rd_ofs, rn_ofs, opr_sz, max_sz, 0, + gen_helper_gvec_urecpe_s); +} + +void gen_gvec_ursqrte(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz) +{ +assert(vece == MO_32); +tcg_gen_gvec_2_ool(rd_ofs, rn_ofs, opr_sz, max_sz, 0, + gen_helper_gvec_ursqrte_s); +} diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c index f9ca889bec..c4fecb8fd6 100644 --- a/target/arm/tcg/translate-neon.c +++ b/target/arm/tcg/translate-neon.c @@ -3070,7 +3070,7 @@ static bool trans_VRECPE(DisasContext *s, arg_2misc *a) if (a->size != 2) { return false; } -return do_2misc(s, a, gen_helper_recpe_u32); +return do_2misc_vec(s, a, gen_gvec_urecpe); } static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) @@ -3078,7 +3078,7 @@ static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) if (a->size != 2) { return false; } -return do_2misc(s, a, gen_helper_rsqrte_u32); +return do_2misc_vec(s, a, gen_gvec_ursqrte); } #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \ diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index 0f4b5670f3..c824e8307b 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -3105,3 +3105,25 @@ void HELPER(gvec_rbit_b)(void *vd, void *vn, uint32_t desc) } clear_tail(d, opr_sz, simd_maxsz(desc)); } + +void HELPER(gvec_urecpe_s)(void *vd, void *vn, uint32_t desc) +{ +intptr_t i, opr_sz = simd_oprsz(desc); +uint32_t *d = vd, *n = vn; + +for (i = 0; i < opr_sz / 4; ++i) { +d[i] = helper_recpe_u32(n[i]); +} +clear_tail(d, opr_sz, simd_maxsz(desc)); +} + +void HELPER(gvec_ursqrte_s)(void *vd, void *vn, uint32_t desc) +{ +intptr_t i, opr_sz = simd_oprsz(desc); +uint32_t *d = vd, *n = vn; + +for (i = 0; i < opr_sz / 4; ++i) { +d[i] = helper_rsqrte_u32(n[i]); +} +clear_tail(d, opr_sz, simd_maxsz(desc)); +} -- 2.43.0
[PATCH v3 26/69] target/arm: Remove helper_sqrt_f16
This function is identical with helper_vfp_sqrth. Replace all uses. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/arm/tcg/helper-a64.h| 1 - target/arm/tcg/helper-a64.c| 11 --- target/arm/tcg/translate-a64.c | 4 ++-- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/target/arm/tcg/helper-a64.h b/target/arm/tcg/helper-a64.h index 481007bf39..203b7b7ac8 100644 --- a/target/arm/tcg/helper-a64.h +++ b/target/arm/tcg/helper-a64.h @@ -80,7 +80,6 @@ DEF_HELPER_2(advsimd_rinth_exact, f16, f16, ptr) DEF_HELPER_2(advsimd_rinth, f16, f16, ptr) DEF_HELPER_2(advsimd_f16tosinth, i32, f16, ptr) DEF_HELPER_2(advsimd_f16touinth, i32, f16, ptr) -DEF_HELPER_2(sqrt_f16, f16, f16, ptr) DEF_HELPER_2(exception_return, void, env, i64) DEF_HELPER_FLAGS_2(dc_zva, TCG_CALL_NO_WG, void, env, i64) diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 8f42a28d07..3f4d7b9aba 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -915,17 +915,6 @@ illegal_return: "resuming execution at 0x%" PRIx64 "\n", cur_el, env->pc); } -/* - * Square Root and Reciprocal square root - */ - -uint32_t HELPER(sqrt_f16)(uint32_t a, void *fpstp) -{ -float_status *s = fpstp; - -return float16_sqrt(a, s); -} - void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in) { uintptr_t ra = GETPC(); diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index cfc73b8506..2a5cb70475 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8354,7 +8354,7 @@ static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn) switch (opcode) { case 0x3: /* FSQRT */ fpst = fpstatus_ptr(FPST_FPCR_F16); -gen_helper_sqrt_f16(tcg_res, tcg_op, fpst); +gen_helper_vfp_sqrth(tcg_res, tcg_op, fpst); break; case 0x8: /* FRINTN */ case 0x9: /* FRINTP */ @@ -10978,7 +10978,7 @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) gen_helper_rsqrte_f16(tcg_res, tcg_op, tcg_fpstatus); break; case 0x7f: /* FSQRT */ -gen_helper_sqrt_f16(tcg_res, tcg_op, tcg_fpstatus); +gen_helper_vfp_sqrth(tcg_res, tcg_op, tcg_fpstatus); break; default: g_assert_not_reached(); -- 2.43.0
[PATCH v3 21/69] target/arm: Introduce fp_access_check_vector_hsd
Provide a simple way to check for float64, float32, and float16 support vs vector width, as well as the fpu enabled. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 135 + 1 file changed, 54 insertions(+), 81 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 4e47b8a804..4611ae4ade 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -1260,6 +1260,28 @@ static int fp_access_check_scalar_hsd(DisasContext *s, MemOp esz) return fp_access_check(s); } +/* Likewise, but vector MO_64 must have two elements. */ +static int fp_access_check_vector_hsd(DisasContext *s, bool is_q, MemOp esz) +{ +switch (esz) { +case MO_64: +if (!is_q) { +return -1; +} +break; +case MO_32: +break; +case MO_16: +if (!dc_isar_feature(aa64_fp16, s)) { +return -1; +} +break; +default: +return -1; +} +return fp_access_check(s); +} + /* * Check that SVE access is enabled. If it is, return true. * If not, emit code to generate an appropriate exception and return false. @@ -5420,27 +5442,14 @@ static bool do_fp3_vector(DisasContext *s, arg_qrrr_e *a, int data, gen_helper_gvec_3_ptr * const fns[3]) { MemOp esz = a->esz; +int check = fp_access_check_vector_hsd(s, a->q, esz); -switch (esz) { -case MO_64: -if (!a->q) { -return false; -} -break; -case MO_32: -break; -case MO_16: -if (!dc_isar_feature(aa64_fp16, s)) { -return false; -} -break; -default: -return false; -} -if (fp_access_check(s)) { -gen_gvec_op3_fpst(s, a->q, a->rd, a->rn, a->rm, - esz == MO_16, data, fns[esz - 1]); +if (check <= 0) { +return check == 0; } + +gen_gvec_op3_fpst(s, a->q, a->rd, a->rn, a->rm, + esz == MO_16, data, fns[esz - 1]); return true; } @@ -5768,34 +5777,24 @@ TRANS_FEAT(FCADD_270, aa64_fcma, do_fp3_vector, a, 1, f_vector_fcadd) static bool trans_FCMLA_v(DisasContext *s, arg_FCMLA_v *a) { -gen_helper_gvec_4_ptr *fn; +static gen_helper_gvec_4_ptr * const fn[] = { +[MO_16] = gen_helper_gvec_fcmlah, +[MO_32] = gen_helper_gvec_fcmlas, +[MO_64] = gen_helper_gvec_fcmlad, +}; +int check; if (!dc_isar_feature(aa64_fcma, s)) { return false; } -switch (a->esz) { -case MO_64: -if (!a->q) { -return false; -} -fn = gen_helper_gvec_fcmlad; -break; -case MO_32: -fn = gen_helper_gvec_fcmlas; -break; -case MO_16: -if (!dc_isar_feature(aa64_fp16, s)) { -return false; -} -fn = gen_helper_gvec_fcmlah; -break; -default: -return false; -} -if (fp_access_check(s)) { -gen_gvec_op4_fpst(s, a->q, a->rd, a->rn, a->rm, a->rd, - a->esz == MO_16, a->rot, fn); + +check = fp_access_check_vector_hsd(s, a->q, a->esz); +if (check <= 0) { +return check == 0; } + +gen_gvec_op4_fpst(s, a->q, a->rd, a->rn, a->rm, a->rd, + a->esz == MO_16, a->rot, fn[a->esz]); return true; } @@ -6337,27 +6336,14 @@ static bool do_fp3_vector_idx(DisasContext *s, arg_qrrx_e *a, gen_helper_gvec_3_ptr * const fns[3]) { MemOp esz = a->esz; +int check = fp_access_check_vector_hsd(s, a->q, esz); -switch (esz) { -case MO_64: -if (!a->q) { -return false; -} -break; -case MO_32: -break; -case MO_16: -if (!dc_isar_feature(aa64_fp16, s)) { -return false; -} -break; -default: -g_assert_not_reached(); -} -if (fp_access_check(s)) { -gen_gvec_op3_fpst(s, a->q, a->rd, a->rn, a->rm, - esz == MO_16, a->idx, fns[esz - 1]); +if (check <= 0) { +return check == 0; } + +gen_gvec_op3_fpst(s, a->q, a->rd, a->rn, a->rm, + esz == MO_16, a->idx, fns[esz - 1]); return true; } @@ -6383,28 +6369,15 @@ static bool do_fmla_vector_idx(DisasContext *s, arg_qrrx_e *a, bool neg) gen_helper_gvec_fmla_idx_d, }; MemOp esz = a->esz; +int check = fp_access_check_vector_hsd(s, a->q, esz); -switch (esz) { -case MO_64: -if (!a->q) { -return false; -} -break; -case MO_32: -break; -case MO_16: -if (!dc_isar_feature(aa64_fp16, s)) { -return false; -} -break; -default: -g_assert_not_reached(); -} -if (fp_access_check(s)) { -gen_gvec_op4_fpst(s, a->q, a->rd, a->rn, a->rm, a-
[PATCH v3 16/69] target/arm: Convert RMIF to decodetree
Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 32 +--- target/arm/tcg/a64.decode | 3 +++ 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index d7747fcf57..1af41e22eb 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8045,30 +8045,18 @@ TRANS(SBC, do_adc_sbc, a, true, false) TRANS(ADCS, do_adc_sbc, a, false, true) TRANS(SBCS, do_adc_sbc, a, true, true) -/* - * Rotate right into flags - * 31 30 2921 15 10 5 4 0 - * +--+--+--+-++---+--+--+--+ - * |sf|op| S| 1 1 0 1 0 0 0 0 | imm6 | 0 0 0 0 1 | Rn |o2| mask | - * +--+--+--+-++---+--+--+--+ - */ -static void disas_rotate_right_into_flags(DisasContext *s, uint32_t insn) +static bool trans_RMIF(DisasContext *s, arg_RMIF *a) { -int mask = extract32(insn, 0, 4); -int o2 = extract32(insn, 4, 1); -int rn = extract32(insn, 5, 5); -int imm6 = extract32(insn, 15, 6); -int sf_op_s = extract32(insn, 29, 3); +int mask = a->mask; TCGv_i64 tcg_rn; TCGv_i32 nzcv; -if (sf_op_s != 5 || o2 != 0 || !dc_isar_feature(aa64_condm_4, s)) { -unallocated_encoding(s); -return; +if (!dc_isar_feature(aa64_condm_4, s)) { +return false; } -tcg_rn = read_cpu_reg(s, rn, 1); -tcg_gen_rotri_i64(tcg_rn, tcg_rn, imm6); +tcg_rn = read_cpu_reg(s, a->rn, 1); +tcg_gen_rotri_i64(tcg_rn, tcg_rn, a->imm); nzcv = tcg_temp_new_i32(); tcg_gen_extrl_i64_i32(nzcv, tcg_rn); @@ -8086,6 +8074,7 @@ static void disas_rotate_right_into_flags(DisasContext *s, uint32_t insn) if (mask & 1) { /* V */ tcg_gen_shli_i32(cpu_VF, nzcv, 31 - 0); } +return true; } /* @@ -8297,11 +8286,6 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) switch (op2) { case 0x0: switch (op3) { -case 0x01: /* Rotate right into flags */ -case 0x21: -disas_rotate_right_into_flags(s, insn); -break; - case 0x02: /* Evaluate into flags */ case 0x12: case 0x22: @@ -8311,6 +8295,8 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) default: case 0x00: /* Add/subtract (with carry) */ +case 0x01: /* Rotate right into flags */ +case 0x21: goto do_unallocated; } break; diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index 7a40ca455e..454494742e 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -753,6 +753,9 @@ SBC . 10 1101 . 00 . . @rrr_sf SBCS. 11 1101 . 00 . . @rrr_sf # Rotate right into flags + +RMIF1 01 1101 imm:6 1 rn:5 0 mask:4 + # Evaluate into flags # Conditional compare (regster) # Conditional compare (immediate) -- 2.43.0
Re: [PATCH v2 04/31] tests/functional: simplify 'which' implementation
On 12/11/24 11:26, Daniel P. Berrangé wrote: The 'access' check implies the file exists. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/cmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index 4106f1ee7c..600e0509db 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -25,7 +25,7 @@ def which(tool): paths=os.getenv('PATH') for p in paths.split(os.path.pathsep): p = os.path.join(p, tool) -if os.path.exists(p) and os.access(p, os.X_OK): +if os.access(p, os.X_OK): return p return None Reviewed-by: Richard Henderson r~
[PATCH 0/3] riscv misaligned accesses
Hi, I fell into some strangeness while using RISCV: * firstly the rvi stores / loads don't seem to generate a trap when doing a misaligned access, which is something we would like to happen. According to the documentation an EEI may or may no guarantee misaligned loads and stores are handled invisibly. Thus PATCH 1 adds an option for enabling those traps, and PATCH 2 raise it when enabled and Zama16B (which implies atomicity for misaligned access within 16bytes boundary) is disabled. * secondly about the conditional store: the documentation states that the Zalrsc extension requires that the address held in rs1 is naturally aligned to the size of the operand. The current implementation doesn't do that check if the store doesn't happen, so the third PATCH fixes that behavior so that a misaligned trap will happen if the address is not naturally aligned even if the store shouldn't happen. Best Regards, Fred Frederic Konrad (3): target/riscv: add a trap-misaligned-access property target/riscv: generate misaligned access trap for rvi insn target/riscv: fix the trap generation for conditional store target/riscv/cpu.c | 5 + target/riscv/cpu_cfg.h | 1 + target/riscv/insn_trans/trans_rva.c.inc | 19 +++ target/riscv/insn_trans/trans_rvi.c.inc | 7 +++ 4 files changed, 32 insertions(+) -- 2.43.5
[PATCH 1/3] target/riscv: add a trap-misaligned-access property
On riscv target, misaligned accesses are either authorized and implemented in hardware, or unimplemented and generate a trap to be implemented in software. At the moment misaligned accesses for rvi just succeed, the intention of this new property is to let the user choose to have a trap when a misaligned access happens. Signed-off-by: Frederic Konrad --- target/riscv/cpu.c | 5 + target/riscv/cpu_cfg.h | 1 + 2 files changed, 6 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f219f0c3b5..1696d3db2a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -2697,6 +2697,11 @@ static Property riscv_cpu_properties[] = { * it with -x and default to 'false'. */ DEFINE_PROP_BOOL("x-misa-w", RISCVCPU, cfg.misa_w, false), +/* + * when set, misaligned accesses will generate a trap. + */ +DEFINE_PROP_BOOL("trap-misaligned-access", RISCVCPU, + cfg.trap_misaligned_access, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index 59d6fc445d..cc560371a1 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -173,6 +173,7 @@ struct RISCVCPUConfig { bool pmp; bool debug; bool misa_w; +bool trap_misaligned_access; bool short_isa_string; -- 2.43.5
[PATCH 2/3] target/riscv: generate misaligned access trap for rvi insn
Now there is an option to enable misaligned accesses traps, check the alignment during load and store for the RVI instructions. Do not generate them if the zama16b extension is there. Signed-off-by: Frederic Konrad --- target/riscv/insn_trans/trans_rvi.c.inc | 7 +++ 1 file changed, 7 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index 96c218a9d7..1283207fc7 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -323,6 +323,10 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop) { bool out; +if (ctx->cfg_ptr->trap_misaligned_access && !ctx->cfg_ptr->ext_zama16b) { +memop |= MO_ALIGN; +} + if (ctx->cfg_ptr->ext_zama16b) { memop |= MO_ATOM_WITHIN16; } @@ -424,6 +428,9 @@ static bool gen_store_i128(DisasContext *ctx, arg_sb *a, MemOp memop) static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop) { +if (ctx->cfg_ptr->trap_misaligned_access && !ctx->cfg_ptr->ext_zama16b) { +memop |= MO_ALIGN; +} if (ctx->cfg_ptr->ext_zama16b) { memop |= MO_ATOM_WITHIN16; } -- 2.43.5
[PATCH 3/3] target/riscv: fix the trap generation for conditional store
>From Unpriviledged ISA manual: "For LR and SC, the Zalrsc extension requires that the address held in rs1 be naturally aligned to the size of the operand (i.e., eight-byte aligned for doublewords and four-byte aligned for words). If the address is not naturally aligned, an address-misaligned exception or an access-fault exception will be generated. The access-fault exception can be generated for a memory access that would otherwise be able to complete except for the misalignment, if the misaligned access should not be emulated." Here nothing checks that the address is naturally aligned, so this fixes that wrong behavior by raising address-misaligned exception if the address in rs1 is not naturally aligned. Signed-off-by: Frederic Konrad --- target/riscv/insn_trans/trans_rva.c.inc | 19 +++ 1 file changed, 19 insertions(+) diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc index 9cf3ae8019..30a047164c 100644 --- a/target/riscv/insn_trans/trans_rva.c.inc +++ b/target/riscv/insn_trans/trans_rva.c.inc @@ -58,11 +58,30 @@ static bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop) static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop) { TCGv dest, src1, src2; +TCGv tmp = tcg_temp_new(); +TCGLabel *l3 = gen_new_label(); TCGLabel *l1 = gen_new_label(); TCGLabel *l2 = gen_new_label(); decode_save_opc(ctx, 0); src1 = get_address(ctx, a->rs1, 0); +/* + * A misaligned store trap should be triggered even if the store should + * fail due to the reservation. + */ +tcg_gen_andi_tl(tmp, src1, ~((uint64_t)0) << memop_alignment_bits(mop)); +tcg_gen_brcond_tl(TCG_COND_EQ, tmp, src1, l3); + +/* + * Store the faulty address, and the actual PC. Then generate the + * exception. + */ +tcg_gen_st_tl(src1, tcg_env, offsetof(CPURISCVState, badaddr)); +gen_pc_plus_diff(cpu_pc, ctx, 0); +gen_helper_raise_exception(tcg_env, + tcg_constant_i32(RISCV_EXCP_STORE_AMO_ADDR_MIS)); + +gen_set_label(l3); tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1); /* -- 2.43.5
Re: [PATCH v2 1/2] os: add an ability to lock memory on_fault
On Wed, Dec 11, 2024 at 03:04:46AM +0300, Daniil Tatianin wrote: > This will be used in the following commits to make it possible to only > lock memory on fault instead of right away. > > Signed-off-by: Daniil Tatianin Reviewed-by: Peter Xu -- Peter Xu
Re: [PATCH 0/3] scripts/qemu-gdb: Make coroutine dumps to work with coredumps
On Wed, Dec 11, 2024 at 05:25:10PM -0300, Fabiano Rosas wrote: > Peter Xu writes: > > > Coroutines are used in many cases in block layers. It's also used in live > > migration when on destination side, and it'll be handy to diagnose crashes > > within a coroutine when we want to also know what other coroutines are > > doing. > > Not sure if you've seen this message on the list: > > https://lore.kernel.org/r/f0ebccca-7a17-4da8-ac4a-71cf6d69a...@mtasv.net No I didn't. I only started looking at this because I got a bug a few days ago that I need to look at the main coroutine where dest crashed, then Stefan told me this script and also told me it only works with live session. Ideally I'll need coredump debug-ability, then I figured it isn't too hard. I saw that it didn't yet land gdb, and it's much more involved even if it could be more generic. Not sure how the block developers think, personally I prefer this much smaller change because it works on old systems, where I can easily install gdb with package managers. -- Peter Xu
Re: [PATCH 2/3] target/riscv: generate misaligned access trap for rvi insn
On 12/11/24 15:19, Frederic Konrad wrote: Now there is an option to enable misaligned accesses traps, check the alignment during load and store for the RVI instructions. Do not generate them if the zama16b extension is there. Signed-off-by: Frederic Konrad --- target/riscv/insn_trans/trans_rvi.c.inc | 7 +++ 1 file changed, 7 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index 96c218a9d7..1283207fc7 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -323,6 +323,10 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop) { bool out; +if (ctx->cfg_ptr->trap_misaligned_access && !ctx->cfg_ptr->ext_zama16b) { +memop |= MO_ALIGN; +} + if (ctx->cfg_ptr->ext_zama16b) { memop |= MO_ATOM_WITHIN16; } @@ -424,6 +428,9 @@ static bool gen_store_i128(DisasContext *ctx, arg_sb *a, MemOp memop) static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop) { +if (ctx->cfg_ptr->trap_misaligned_access && !ctx->cfg_ptr->ext_zama16b) { +memop |= MO_ALIGN; +} if (ctx->cfg_ptr->ext_zama16b) { memop |= MO_ATOM_WITHIN16; } I would imagine that ext_zama16b would disable or conflict with trap_misaligned_access at startup. r~
Re: [PATCH v2 2/2] overcommit: introduce mem-lock=on-fault
On Wed, Dec 11, 2024 at 03:04:47AM +0300, Daniil Tatianin wrote: > Locking the memory without MCL_ONFAULT instantly prefaults any mmaped > anonymous memory with a write-fault, which introduces a lot of extra > overhead in terms of memory usage when all you want to do is to prevent > kcompactd from migrating and compacting QEMU pages. Add an option to > only lock pages lazily as they're faulted by the process by using > MCL_ONFAULT if asked. Looks good but some nitpicks below.. > > Signed-off-by: Daniil Tatianin > --- > include/sysemu/sysemu.h | 1 + > migration/postcopy-ram.c | 4 ++-- > qemu-options.hx | 14 +++- > system/globals.c | 1 + > system/vl.c | 46 > 5 files changed, 50 insertions(+), 16 deletions(-) > > diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h > index 7ec419ce13..b6519c3c1e 100644 > --- a/include/sysemu/sysemu.h > +++ b/include/sysemu/sysemu.h > @@ -44,6 +44,7 @@ extern const char *keyboard_layout; > extern int old_param; > extern uint8_t *boot_splash_filedata; > extern bool enable_mlock; > +extern bool enable_mlock_onfault; > extern bool enable_cpu_pm; > extern QEMUClockType rtc_clock; > > diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c > index 36ec6a3d75..8ff8c73a27 100644 > --- a/migration/postcopy-ram.c > +++ b/migration/postcopy-ram.c > @@ -651,8 +651,8 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState > *mis) > mis->have_fault_thread = false; > } > > -if (enable_mlock) { > -if (os_mlock(false) < 0) { > +if (enable_mlock || enable_mlock_onfault) { > +if (os_mlock(enable_mlock_onfault) < 0) { > error_report("mlock: %s", strerror(errno)); > /* > * It doesn't feel right to fail at this point, we have a valid > diff --git a/qemu-options.hx b/qemu-options.hx > index dacc9790a4..6c8360e62e 100644 > --- a/qemu-options.hx > +++ b/qemu-options.hx > @@ -4566,21 +4566,25 @@ SRST > ERST > > DEF("overcommit", HAS_ARG, QEMU_OPTION_overcommit, > -"-overcommit [mem-lock=on|off][cpu-pm=on|off]\n" > +"-overcommit [mem-lock=on|off|on-fault][cpu-pm=on|off]\n" > "run qemu with overcommit hints\n" > -"mem-lock=on|off controls memory lock support (default: > off)\n" > +"mem-lock=on|off|on-fault controls memory lock support > (default: off)\n" > "cpu-pm=on|off controls cpu power management (default: > off)\n", > QEMU_ARCH_ALL) > SRST > -``-overcommit mem-lock=on|off`` > +``-overcommit mem-lock=on|off|on-fault`` >\ > ``-overcommit cpu-pm=on|off`` > Run qemu with hints about host resource overcommit. The default is > to assume that host overcommits all resources. > > Locking qemu and guest memory can be enabled via ``mem-lock=on`` > -(disabled by default). This works when host memory is not > -overcommitted and reduces the worst-case latency for guest. > +or ``mem-lock=on-fault`` (disabled by default). This works when > +host memory is not overcommitted and reduces the worst-case latency for > +guest. The on-fault option is better for reducing the memory footprint > +since it makes allocations lazy, but the pages still get locked in place > +once faulted by the guest or QEMU. Note that the two options are mutually > +exclusive. > > Guest ability to manage power state of host cpus (increasing latency > for other processes on the same host cpu, but decreasing latency for > diff --git a/system/globals.c b/system/globals.c > index 84ce943ac9..43501fe690 100644 > --- a/system/globals.c > +++ b/system/globals.c > @@ -35,6 +35,7 @@ enum vga_retrace_method vga_retrace_method = > VGA_RETRACE_DUMB; > int display_opengl; > const char* keyboard_layout; > bool enable_mlock; > +bool enable_mlock_onfault; > bool enable_cpu_pm; > int autostart = 1; > int vga_interface_type = VGA_NONE; > diff --git a/system/vl.c b/system/vl.c > index 03819a80ef..4e2efd3ad4 100644 > --- a/system/vl.c > +++ b/system/vl.c > @@ -347,7 +347,7 @@ static QemuOptsList qemu_overcommit_opts = { > .desc = { > { > .name = "mem-lock", > -.type = QEMU_OPT_BOOL, > +.type = QEMU_OPT_STRING, > }, > { > .name = "cpu-pm", > @@ -792,8 +792,8 @@ static QemuOptsList qemu_run_with_opts = { > > static void realtime_init(void) > { > -if (enable_mlock) { > -if (os_mlock(false) < 0) { > +if (enable_mlock || enable_mlock_onfault) { IIUC it's still cleaner to make enable_mlock into an enum to be a tri-state. IOW, we could have two flags set now with the current patch when with things like: -overcommit mem-lock=on -overcommit mem-lock=on-fault > +if (os_mlock(enable_mlock_onfault) < 0) { > error_report("locking memory failed"); > exit(1); >
Re: [PATCH 3/3] target/riscv: fix the trap generation for conditional store
On 12/11/24 15:19, Frederic Konrad wrote: +/* + * A misaligned store trap should be triggered even if the store should + * fail due to the reservation. + */ +tcg_gen_andi_tl(tmp, src1, ~((uint64_t)0) << memop_alignment_bits(mop)); The constant is incorrect for testing the low bits. +tcg_gen_brcond_tl(TCG_COND_EQ, tmp, src1, l3); Best to make the fallthrough path be the common case, as we will optimize across the extended basic block. Use test-style comparison: tcg_gen_brcondi_tl(TCG_COND_TSTNE, src1, memop_size(mop) - 1, l_misalign); r~
Re: [PATCH v2 2/2] overcommit: introduce mem-lock=on-fault
On 12/12/24 12:52 AM, Peter Xu wrote: On Wed, Dec 11, 2024 at 03:04:47AM +0300, Daniil Tatianin wrote: Locking the memory without MCL_ONFAULT instantly prefaults any mmaped anonymous memory with a write-fault, which introduces a lot of extra overhead in terms of memory usage when all you want to do is to prevent kcompactd from migrating and compacting QEMU pages. Add an option to only lock pages lazily as they're faulted by the process by using MCL_ONFAULT if asked. Looks good but some nitpicks below.. Signed-off-by: Daniil Tatianin --- include/sysemu/sysemu.h | 1 + migration/postcopy-ram.c | 4 ++-- qemu-options.hx | 14 +++- system/globals.c | 1 + system/vl.c | 46 5 files changed, 50 insertions(+), 16 deletions(-) diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 7ec419ce13..b6519c3c1e 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -44,6 +44,7 @@ extern const char *keyboard_layout; extern int old_param; extern uint8_t *boot_splash_filedata; extern bool enable_mlock; +extern bool enable_mlock_onfault; extern bool enable_cpu_pm; extern QEMUClockType rtc_clock; diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 36ec6a3d75..8ff8c73a27 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -651,8 +651,8 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis) mis->have_fault_thread = false; } -if (enable_mlock) { -if (os_mlock(false) < 0) { +if (enable_mlock || enable_mlock_onfault) { +if (os_mlock(enable_mlock_onfault) < 0) { error_report("mlock: %s", strerror(errno)); /* * It doesn't feel right to fail at this point, we have a valid diff --git a/qemu-options.hx b/qemu-options.hx index dacc9790a4..6c8360e62e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4566,21 +4566,25 @@ SRST ERST DEF("overcommit", HAS_ARG, QEMU_OPTION_overcommit, -"-overcommit [mem-lock=on|off][cpu-pm=on|off]\n" +"-overcommit [mem-lock=on|off|on-fault][cpu-pm=on|off]\n" "run qemu with overcommit hints\n" -"mem-lock=on|off controls memory lock support (default: off)\n" +"mem-lock=on|off|on-fault controls memory lock support (default: off)\n" "cpu-pm=on|off controls cpu power management (default: off)\n", QEMU_ARCH_ALL) SRST -``-overcommit mem-lock=on|off`` +``-overcommit mem-lock=on|off|on-fault`` \ ``-overcommit cpu-pm=on|off`` Run qemu with hints about host resource overcommit. The default is to assume that host overcommits all resources. Locking qemu and guest memory can be enabled via ``mem-lock=on`` -(disabled by default). This works when host memory is not -overcommitted and reduces the worst-case latency for guest. +or ``mem-lock=on-fault`` (disabled by default). This works when +host memory is not overcommitted and reduces the worst-case latency for +guest. The on-fault option is better for reducing the memory footprint +since it makes allocations lazy, but the pages still get locked in place +once faulted by the guest or QEMU. Note that the two options are mutually +exclusive. Guest ability to manage power state of host cpus (increasing latency for other processes on the same host cpu, but decreasing latency for diff --git a/system/globals.c b/system/globals.c index 84ce943ac9..43501fe690 100644 --- a/system/globals.c +++ b/system/globals.c @@ -35,6 +35,7 @@ enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; int display_opengl; const char* keyboard_layout; bool enable_mlock; +bool enable_mlock_onfault; bool enable_cpu_pm; int autostart = 1; int vga_interface_type = VGA_NONE; diff --git a/system/vl.c b/system/vl.c index 03819a80ef..4e2efd3ad4 100644 --- a/system/vl.c +++ b/system/vl.c @@ -347,7 +347,7 @@ static QemuOptsList qemu_overcommit_opts = { .desc = { { .name = "mem-lock", -.type = QEMU_OPT_BOOL, +.type = QEMU_OPT_STRING, }, { .name = "cpu-pm", @@ -792,8 +792,8 @@ static QemuOptsList qemu_run_with_opts = { static void realtime_init(void) { -if (enable_mlock) { -if (os_mlock(false) < 0) { +if (enable_mlock || enable_mlock_onfault) { IIUC it's still cleaner to make enable_mlock into an enum to be a tri-state. IOW, we could have two flags set now with the current patch when with things like: -overcommit mem-lock=on -overcommit mem-lock=on-fault Oh yeah good catch, that's a problem. +if (os_mlock(enable_mlock_onfault) < 0) { error_report("locking memory failed"); exit(1); } @@ -3532,14 +3532,42 @@ void qemu_init(int argc, char **argv) object_op
Re: [PATCH V4 14/19] migration: cpr-transfer mode
On 12/10/2024 7:26 AM, Markus Armbruster wrote: Steve Sistare writes: Add the cpr-transfer migration mode. Usage: qemu-system-$arch -machine aux-ram-share=on ... start new QEMU with "-incoming -incoming " Issue commands to old QEMU: migrate_set_parameter mode cpr-transfer {"execute": "migrate", ... {"channel-type": "main"...}, {"channel-type": "cpr"...} ... } Much technical detail here that won't make sense to the reader until further down, but next to nothing on what the thing actually accomplishes. Makes the commit message unnecessarily hard to understand. But please read on. The migrate command stops the VM, saves CPR state to cpr-channel, saves normal migration state to main-uri, and old QEMU enters the postmigrate state. The user starts new QEMU on the same host as old QEMU, with the same arguments as old QEMU, Any additional requirements over traditional migration? There, "same arguments" is sufficient, but not necessary. For instance, changing certain backends is quite possible. No additional requirements over traditional migration. AFAIK there is no user documentation on what arguments must be specified to new QEMU during a migration. No words about "same arguments", or even "same VM". I am trying to give some guidance where none currently exists, in this commit message and in QAPI for CPR. Perhaps this is better: The user starts new QEMU on the same host as old QEMU, with command-line arguments to create the same machine, plus the -incoming option for the main migration channel, like normal live migration. In addition, the user adds a second -incoming option with channel type "cpr", which matches the cpr channel of the migrate command issued to old QEMU. plus two -incoming options. Two -incoming options to define two migration channels, the traditional one of MigrationChannelType "main", and an another one of MigrationChannelType "cpr"? Yes. I will elaborate. Guest RAM is preserved in place, albeit with new virtual addresses in new QEMU. This mode requires a second migration channel of type "cpr", in the channel arguments on the outgoing side, and in a second -incoming command-line parameter on the incoming side. Memory-backend objects must have the share=on attribute, but memory-backend-epc is not supported. The VM must be started with the '-machine aux-ram-share=on' option, which allows anonymous memory to be transferred in place to the new process. The memfds are kept open by sending the descriptors to new QEMU via the CPR channel, which must support SCM_RIGHTS, and they are mmap'd in new QEMU. The implementation splits qmp_migrate into start and finish functions. Start sends CPR state to new QEMU, which responds by closing the CPR channel. Old QEMU detects the HUP then calls finish, which connects the main migration channel. Signed-off-by: Steve Sistare I'd lead with a brief explanation of the feature and its benefits. Could steam from the cover letter like this: New migration mode cpr-transfer mode enables transferring a guest to a new QEMU instance on the same host with minimal guest pause time, by preserving guest RAM in place, albeit with new virtual addresses in new QEMU, and by preserving device file descriptors. Then talk about required special setup. I see aux-ram-share=on. Anything else? Any differences between source and destination QEMU there? Then talk about the two channels. First what they do, second how to create their destination end with -incoming, third how to create their source end with "migrate". Finally mention whatever technical detail you believe needs mentioning here. I'll work on it. [...] diff --git a/qapi/migration.json b/qapi/migration.json index a26960b..1bc963f 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -614,9 +614,44 @@ # or COLO. # # (since 8.2) +# +# @cpr-transfer: This mode allows the user to transfer a guest to a +# new QEMU instance on the same host with minimal guest pause +# time, by preserving guest RAM in place, albeit with new virtual +# addresses in new QEMU. +# +# The user starts new QEMU on the same host as old QEMU, with the +# the same arguments as old QEMU, plus the -incoming option. Two of them? Yes, I will say more. +# The +# user issues the migrate command to old QEMU, which stops the VM, +# saves state to the migration channels, and enters the +# postmigrate state. Execution resumes in new QEMU. The commit message also mentions file descriptors are migrared over. Worth mentioning here, too? IMO no. The user cannot observe that aspect, so they don't need to know. It's an implementation detail. +# +# This mode requires a second migration channel type "cpr" in the +# channel arguments on the outgoing sid
Re: [PATCH] tcg/riscv: Fix StoreStore barrier generation
On 12/11/24 01:40, Roman Artemev wrote: On RISC-V to StoreStore barrier corresponds `fence w, w` not `fence r, r` Signed-off-by: Denis Tomashev Signed-off-by: Roman Artemev --- tcg/riscv/tcg-target.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index f8331e4688..96f9a7e348 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1624,7 +1624,7 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0) insn |= 0x0210; } if (a0 & TCG_MO_ST_ST) { -insn |= 0x0220; +insn |= 0x0110; } tcg_out32(s, insn); } Fixes: efbea94c76b ("tcg/riscv: Add slowpath load and store instructions") Reviewed-by: Richard Henderson Wow, that typo has been around for a while. Thanks, queued. r~
[PATCH v3 11/69] target/arm: Convert disas_logic_reg to decodetree
This includes AND, BIC, ORR, ORN, EOR, EON, ANDS, BICS (shifted reg). Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 117 - target/arm/tcg/a64.decode | 9 +++ 2 files changed, 51 insertions(+), 75 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index d92fe68299..ecc8899dd8 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -7805,96 +7805,65 @@ static bool do_xpac(DisasContext *s, int rd, NeonGenOne64OpEnvFn *fn) TRANS_FEAT(XPACI, aa64_pauth, do_xpac, a->rd, gen_helper_xpaci) TRANS_FEAT(XPACD, aa64_pauth, do_xpac, a->rd, gen_helper_xpacd) -/* Logical (shifted register) - * 31 30 29 28 24 23 22 21 20 16 1510 95 40 - * ++-+---+---+---+--++--+--+ - * | sf | opc | 0 1 0 1 0 | shift | N | Rm | imm6 | Rn | Rd | - * ++-+---+---+---+--++--+--+ - */ -static void disas_logic_reg(DisasContext *s, uint32_t insn) +static bool do_logic_reg(DisasContext *s, arg_logic_shift *a, + ArithTwoOp *fn, ArithTwoOp *inv_fn, bool setflags) { TCGv_i64 tcg_rd, tcg_rn, tcg_rm; -unsigned int sf, opc, shift_type, invert, rm, shift_amount, rn, rd; -sf = extract32(insn, 31, 1); -opc = extract32(insn, 29, 2); -shift_type = extract32(insn, 22, 2); -invert = extract32(insn, 21, 1); -rm = extract32(insn, 16, 5); -shift_amount = extract32(insn, 10, 6); -rn = extract32(insn, 5, 5); -rd = extract32(insn, 0, 5); - -if (!sf && (shift_amount & (1 << 5))) { -unallocated_encoding(s); -return; +if (!a->sf && (a->sa & (1 << 5))) { +return false; } -tcg_rd = cpu_reg(s, rd); +tcg_rd = cpu_reg(s, a->rd); +tcg_rn = cpu_reg(s, a->rn); -if (opc == 1 && shift_amount == 0 && shift_type == 0 && rn == 31) { -/* Unshifted ORR and ORN with WZR/XZR is the standard encoding for - * register-register MOV and MVN, so it is worth special casing. - */ -tcg_rm = cpu_reg(s, rm); -if (invert) { +tcg_rm = read_cpu_reg(s, a->rm, a->sf); +if (a->sa) { +shift_reg_imm(tcg_rm, tcg_rm, a->sf, a->st, a->sa); +} + +(a->n ? inv_fn : fn)(tcg_rd, tcg_rn, tcg_rm); +if (!a->sf) { +tcg_gen_ext32u_i64(tcg_rd, tcg_rd); +} +if (setflags) { +gen_logic_CC(a->sf, tcg_rd); +} +return true; +} + +static bool trans_ORR_r(DisasContext *s, arg_logic_shift *a) +{ +/* + * Unshifted ORR and ORN with WZR/XZR is the standard encoding for + * register-register MOV and MVN, so it is worth special casing. + */ +if (a->sa == 0 && a->st == 0 && a->rn == 31) { +TCGv_i64 tcg_rd = cpu_reg(s, a->rd); +TCGv_i64 tcg_rm = cpu_reg(s, a->rm); + +if (a->n) { tcg_gen_not_i64(tcg_rd, tcg_rm); -if (!sf) { +if (!a->sf) { tcg_gen_ext32u_i64(tcg_rd, tcg_rd); } } else { -if (sf) { +if (a->sf) { tcg_gen_mov_i64(tcg_rd, tcg_rm); } else { tcg_gen_ext32u_i64(tcg_rd, tcg_rm); } } -return; +return true; } -tcg_rm = read_cpu_reg(s, rm, sf); - -if (shift_amount) { -shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, shift_amount); -} - -tcg_rn = cpu_reg(s, rn); - -switch (opc | (invert << 2)) { -case 0: /* AND */ -case 3: /* ANDS */ -tcg_gen_and_i64(tcg_rd, tcg_rn, tcg_rm); -break; -case 1: /* ORR */ -tcg_gen_or_i64(tcg_rd, tcg_rn, tcg_rm); -break; -case 2: /* EOR */ -tcg_gen_xor_i64(tcg_rd, tcg_rn, tcg_rm); -break; -case 4: /* BIC */ -case 7: /* BICS */ -tcg_gen_andc_i64(tcg_rd, tcg_rn, tcg_rm); -break; -case 5: /* ORN */ -tcg_gen_orc_i64(tcg_rd, tcg_rn, tcg_rm); -break; -case 6: /* EON */ -tcg_gen_eqv_i64(tcg_rd, tcg_rn, tcg_rm); -break; -default: -assert(FALSE); -break; -} - -if (!sf) { -tcg_gen_ext32u_i64(tcg_rd, tcg_rd); -} - -if (opc == 3) { -gen_logic_CC(sf, tcg_rd); -} +return do_logic_reg(s, a, tcg_gen_or_i64, tcg_gen_orc_i64, false); } +TRANS(AND_r, do_logic_reg, a, tcg_gen_and_i64, tcg_gen_andc_i64, false) +TRANS(ANDS_r, do_logic_reg, a, tcg_gen_and_i64, tcg_gen_andc_i64, true) +TRANS(EOR_r, do_logic_reg, a, tcg_gen_xor_i64, tcg_gen_eqv_i64, false) + /* * Add/subtract (extended register) * @@ -8411,11 +8380,9 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) /* Add/sub (shifted register) */ disas_add_sub_reg(s, insn); } -} else { -/* Logical (shifted register) */ -disas_logic_reg(
[PATCH v3 13/69] target/arm: Convert disas_add_sub_reg to decodetree
This includes ADD, SUB, ADDS, SUBS (shifted register). Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 64 ++ target/arm/tcg/a64.decode | 9 + 2 files changed, 27 insertions(+), 46 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 8f777875fe..d570bbb696 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -7912,47 +7912,22 @@ TRANS(SUB_ext, do_addsub_ext, a, true, false) TRANS(ADDS_ext, do_addsub_ext, a, false, true) TRANS(SUBS_ext, do_addsub_ext, a, true, true) -/* - * Add/subtract (shifted register) - * - * 31 30 29 28 24 23 22 21 20 16 15 10 95 40 - * +--+--+--+---+-+--+---+-+--+--+ - * |sf|op| S| 0 1 0 1 1 |shift| 0| Rm | imm6 | Rn | Rd | - * +--+--+--+---+-+--+---+-+--+--+ - * - *sf: 0 -> 32bit, 1 -> 64bit - *op: 0 -> add , 1 -> sub - * S: 1 -> set flags - * shift: 00 -> LSL, 01 -> LSR, 10 -> ASR, 11 -> RESERVED - * imm6: Shift amount to apply to Rm before the add/sub - */ -static void disas_add_sub_reg(DisasContext *s, uint32_t insn) +static bool do_addsub_reg(DisasContext *s, arg_addsub_shift *a, + bool sub_op, bool setflags) { -int rd = extract32(insn, 0, 5); -int rn = extract32(insn, 5, 5); -int imm6 = extract32(insn, 10, 6); -int rm = extract32(insn, 16, 5); -int shift_type = extract32(insn, 22, 2); -bool setflags = extract32(insn, 29, 1); -bool sub_op = extract32(insn, 30, 1); -bool sf = extract32(insn, 31, 1); +TCGv_i64 tcg_rd, tcg_rn, tcg_rm, tcg_result; -TCGv_i64 tcg_rd = cpu_reg(s, rd); -TCGv_i64 tcg_rn, tcg_rm; -TCGv_i64 tcg_result; - -if ((shift_type == 3) || (!sf && (imm6 > 31))) { -unallocated_encoding(s); -return; +if (a->st == 3 || (!a->sf && (a->sa & 32))) { +return false; } -tcg_rn = read_cpu_reg(s, rn, sf); -tcg_rm = read_cpu_reg(s, rm, sf); +tcg_rd = cpu_reg(s, a->rd); +tcg_rn = read_cpu_reg(s, a->rn, a->sf); +tcg_rm = read_cpu_reg(s, a->rm, a->sf); -shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6); +shift_reg_imm(tcg_rm, tcg_rm, a->sf, a->st, a->sa); tcg_result = tcg_temp_new_i64(); - if (!setflags) { if (sub_op) { tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm); @@ -7961,19 +7936,25 @@ static void disas_add_sub_reg(DisasContext *s, uint32_t insn) } } else { if (sub_op) { -gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm); +gen_sub_CC(a->sf, tcg_result, tcg_rn, tcg_rm); } else { -gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm); +gen_add_CC(a->sf, tcg_result, tcg_rn, tcg_rm); } } -if (sf) { +if (a->sf) { tcg_gen_mov_i64(tcg_rd, tcg_result); } else { tcg_gen_ext32u_i64(tcg_rd, tcg_result); } +return true; } +TRANS(ADD_r, do_addsub_reg, a, false, false) +TRANS(SUB_r, do_addsub_reg, a, true, false) +TRANS(ADDS_r, do_addsub_reg, a, false, true) +TRANS(SUBS_r, do_addsub_reg, a, true, true) + /* Data-processing (3 source) * *31 30 29 28 24 23 21 20 16 15 14 10 95 40 @@ -8348,15 +8329,6 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) int op3 = extract32(insn, 10, 6); if (!op1) { -if (op2 & 8) { -if (op2 & 1) { -goto do_unallocated; -} else { -/* Add/sub (shifted register) */ -disas_add_sub_reg(s, insn); -} -return; -} goto do_unallocated; } diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index 0539694506..27a3101bc6 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -726,6 +726,15 @@ EOR_r . 10 01010 .. . . .. . . @logic_shift ANDS_r . 11 01010 .. . . .. . .@logic_shift # Add/subtract (shifted reg) + +&addsub_shiftrd rn rm sf sa st +@addsub_shiftsf:1 .. . st:2 . rm:5 sa:6 rn:5 rd:5 &addsub_shift + +ADD_r . 00 01011 .. 0 . .. . .@addsub_shift +SUB_r . 10 01011 .. 0 . .. . .@addsub_shift +ADDS_r . 01 01011 .. 0 . .. . .@addsub_shift +SUBS_r . 11 01011 .. 0 . .. . .@addsub_shift + # Add/subtract (extended reg) &addsub_ext rd rn rm sf sa st -- 2.43.0
[PATCH v3 22/69] target/arm: Convert FCMP, FCMPE, FCCMP, FCCMPE to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 283 - target/arm/tcg/a64.decode | 8 + 2 files changed, 112 insertions(+), 179 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 4611ae4ade..a99f3d0d13 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -6888,6 +6888,106 @@ static bool trans_FMOVI_s(DisasContext *s, arg_FMOVI_s *a) return true; } +/* + * Floating point compare, conditional compare + */ + +static void handle_fp_compare(DisasContext *s, int size, + unsigned int rn, unsigned int rm, + bool cmp_with_zero, bool signal_all_nans) +{ +TCGv_i64 tcg_flags = tcg_temp_new_i64(); +TCGv_ptr fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); + +if (size == MO_64) { +TCGv_i64 tcg_vn, tcg_vm; + +tcg_vn = read_fp_dreg(s, rn); +if (cmp_with_zero) { +tcg_vm = tcg_constant_i64(0); +} else { +tcg_vm = read_fp_dreg(s, rm); +} +if (signal_all_nans) { +gen_helper_vfp_cmped_a64(tcg_flags, tcg_vn, tcg_vm, fpst); +} else { +gen_helper_vfp_cmpd_a64(tcg_flags, tcg_vn, tcg_vm, fpst); +} +} else { +TCGv_i32 tcg_vn = tcg_temp_new_i32(); +TCGv_i32 tcg_vm = tcg_temp_new_i32(); + +read_vec_element_i32(s, tcg_vn, rn, 0, size); +if (cmp_with_zero) { +tcg_gen_movi_i32(tcg_vm, 0); +} else { +read_vec_element_i32(s, tcg_vm, rm, 0, size); +} + +switch (size) { +case MO_32: +if (signal_all_nans) { +gen_helper_vfp_cmpes_a64(tcg_flags, tcg_vn, tcg_vm, fpst); +} else { +gen_helper_vfp_cmps_a64(tcg_flags, tcg_vn, tcg_vm, fpst); +} +break; +case MO_16: +if (signal_all_nans) { +gen_helper_vfp_cmpeh_a64(tcg_flags, tcg_vn, tcg_vm, fpst); +} else { +gen_helper_vfp_cmph_a64(tcg_flags, tcg_vn, tcg_vm, fpst); +} +break; +default: +g_assert_not_reached(); +} +} + +gen_set_nzcv(tcg_flags); +} + +/* FCMP, FCMPE */ +static bool trans_FCMP(DisasContext *s, arg_FCMP *a) +{ +int check = fp_access_check_scalar_hsd(s, a->esz); + +if (check <= 0) { +return check == 0; +} + +handle_fp_compare(s, a->esz, a->rn, a->rm, a->z, a->e); +return true; +} + +/* FCCMP, FCCMPE */ +static bool trans_FCCMP(DisasContext *s, arg_FCCMP *a) +{ +TCGLabel *label_continue = NULL; +int check = fp_access_check_scalar_hsd(s, a->esz); + +if (check <= 0) { +return check == 0; +} + +if (a->cond < 0x0e) { /* not always */ +TCGLabel *label_match = gen_new_label(); +label_continue = gen_new_label(); +arm_gen_test_cc(a->cond, label_match); +/* nomatch: */ +gen_set_nzcv(tcg_constant_i64(a->nzcv << 28)); +tcg_gen_br(label_continue); +gen_set_label(label_match); +} + +handle_fp_compare(s, a->esz, a->rn, a->rm, false, a->e); + +if (label_continue) { +gen_set_label(label_continue); +} +return true; +} + /* * Advanced SIMD Modified Immediate */ @@ -8183,174 +8283,6 @@ static bool trans_CSEL(DisasContext *s, arg_CSEL *a) return true; } -static void handle_fp_compare(DisasContext *s, int size, - unsigned int rn, unsigned int rm, - bool cmp_with_zero, bool signal_all_nans) -{ -TCGv_i64 tcg_flags = tcg_temp_new_i64(); -TCGv_ptr fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); - -if (size == MO_64) { -TCGv_i64 tcg_vn, tcg_vm; - -tcg_vn = read_fp_dreg(s, rn); -if (cmp_with_zero) { -tcg_vm = tcg_constant_i64(0); -} else { -tcg_vm = read_fp_dreg(s, rm); -} -if (signal_all_nans) { -gen_helper_vfp_cmped_a64(tcg_flags, tcg_vn, tcg_vm, fpst); -} else { -gen_helper_vfp_cmpd_a64(tcg_flags, tcg_vn, tcg_vm, fpst); -} -} else { -TCGv_i32 tcg_vn = tcg_temp_new_i32(); -TCGv_i32 tcg_vm = tcg_temp_new_i32(); - -read_vec_element_i32(s, tcg_vn, rn, 0, size); -if (cmp_with_zero) { -tcg_gen_movi_i32(tcg_vm, 0); -} else { -read_vec_element_i32(s, tcg_vm, rm, 0, size); -} - -switch (size) { -case MO_32: -if (signal_all_nans) { -gen_helper_vfp_cmpes_a64(tcg_flags, tcg_vn, tcg_vm, fpst); -} else { -gen_helper_vfp_cmps_a64(tcg_flags, tcg_vn, tcg_vm, fpst); -} -break; -case MO_16: -if (signal_all_nans) { -gen_helper_
[PATCH v3 58/69] target/arm: Convert FCVT* (vector, fixed-point) scalar to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 4 +--- target/arm/tcg/a64.decode | 19 +++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 71f1d6f778..894befef4d 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -9535,9 +9535,6 @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) handle_simd_shift_intfp_conv(s, true, false, is_u, immh, immb, opcode, rn, rd); break; -case 0x1f: /* FCVTZS, FCVTZU */ -handle_simd_shift_fpint_conv(s, true, false, is_u, immh, immb, rn, rd); -break; default: case 0x00: /* SSHR / USHR */ case 0x02: /* SSRA / USRA */ @@ -9551,6 +9548,7 @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) case 0x11: /* SQRSHRUN */ case 0x12: /* SQSHRN, UQSHRN */ case 0x13: /* SQRSHRN, UQRSHRN */ +case 0x1f: /* FCVTZS, FCVTZU */ unallocated_encoding(s); break; } diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index f7fcc32adc..f66f62da4f 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -1682,6 +1682,25 @@ FCVTAS_f0101 1110 0.1 1 11001 0 . . @icvt_sd FCVTAU_f0111 1110 011 11001 11001 0 . . @icvt_h FCVTAU_f0111 1110 0.1 1 11001 0 . . @icvt_sd +%fcvt_f_sh_h16:4 !function=rsub_16 +%fcvt_f_sh_s16:5 !function=rsub_32 +%fcvt_f_sh_d16:6 !function=rsub_64 + +@fcvt_fixed_h . 001 .. rn:5 rd:5 \ +&fcvt sf=0 esz=1 shift=%fcvt_f_sh_h +@fcvt_fixed_s . 01 . .. rn:5 rd:5 \ +&fcvt sf=0 esz=2 shift=%fcvt_f_sh_s +@fcvt_fixed_d . 1 .. .. rn:5 rd:5 \ +&fcvt sf=0 esz=3 shift=%fcvt_f_sh_d + +FCVTZS_f0101 0 ... 11 . . @fcvt_fixed_h +FCVTZS_f0101 0 ... 11 . . @fcvt_fixed_s +FCVTZS_f0101 0 ... 11 . . @fcvt_fixed_d + +FCVTZU_f0111 0 ... 11 . . @fcvt_fixed_h +FCVTZU_f0111 0 ... 11 . . @fcvt_fixed_s +FCVTZU_f0111 0 ... 11 . . @fcvt_fixed_d + # Advanced SIMD two-register miscellaneous SQABS_v 0.00 1110 ..1 0 0 0 . . @qrr_e -- 2.43.0
[PATCH v3 45/69] target/arm: Introduce gen_gvec_{s,u}{add,ada}lp
Pairwise addition with and without accumulation. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/helper.h | 2 - target/arm/tcg/translate.h | 9 ++ target/arm/tcg/gengvec.c| 230 target/arm/tcg/neon_helper.c| 22 --- target/arm/tcg/translate-neon.c | 150 + 5 files changed, 243 insertions(+), 170 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 57e0ce387b..6369d07d05 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -397,8 +397,6 @@ DEF_HELPER_1(neon_widen_s16, i64, i32) DEF_HELPER_2(neon_addl_u16, i64, i64, i64) DEF_HELPER_2(neon_addl_u32, i64, i64, i64) -DEF_HELPER_2(neon_paddl_u16, i64, i64, i64) -DEF_HELPER_2(neon_paddl_u32, i64, i64, i64) DEF_HELPER_FLAGS_1(neon_addlp_s8, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(neon_addlp_s16, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_2(neon_subl_u16, i64, i64, i64) diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index 342ebedafc..edd775d564 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -593,6 +593,15 @@ void gen_gvec_rev32(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, void gen_gvec_rev64(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_saddlp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_sadalp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_uaddlp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz); +void gen_gvec_uadalp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz); + /* * Forward to the isar_feature_* tests given a DisasContext pointer. */ diff --git a/target/arm/tcg/gengvec.c b/target/arm/tcg/gengvec.c index 33c0a94958..2755da8ac7 100644 --- a/target/arm/tcg/gengvec.c +++ b/target/arm/tcg/gengvec.c @@ -2467,3 +2467,233 @@ void gen_gvec_rev64(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, g_assert_not_reached(); } } + +static void gen_saddlp_vec(unsigned vece, TCGv_vec d, TCGv_vec n) +{ +int half = 4 << vece; +TCGv_vec t = tcg_temp_new_vec_matching(d); + +tcg_gen_shli_vec(vece, t, n, half); +tcg_gen_sari_vec(vece, d, n, half); +tcg_gen_sari_vec(vece, t, t, half); +tcg_gen_add_vec(vece, d, d, t); +} + +static void gen_saddlp_s_i64(TCGv_i64 d, TCGv_i64 n) +{ +TCGv_i64 t = tcg_temp_new_i64(); + +tcg_gen_ext32s_i64(t, n); +tcg_gen_sari_i64(d, n, 32); +tcg_gen_add_i64(d, d, t); +} + +void gen_gvec_saddlp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz) +{ +static const TCGOpcode vecop_list[] = { +INDEX_op_sari_vec, INDEX_op_shli_vec, INDEX_op_add_vec, 0 +}; +static const GVecGen2 g[] = { +{ .fniv = gen_saddlp_vec, + .fni8 = gen_helper_neon_addlp_s8, + .opt_opc = vecop_list, + .vece = MO_16 }, +{ .fniv = gen_saddlp_vec, + .fni8 = gen_helper_neon_addlp_s16, + .opt_opc = vecop_list, + .vece = MO_32 }, +{ .fniv = gen_saddlp_vec, + .fni8 = gen_saddlp_s_i64, + .opt_opc = vecop_list, + .vece = MO_64 }, +}; +assert(vece <= MO_32); +tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g[vece]); +} + +static void gen_sadalp_vec(unsigned vece, TCGv_vec d, TCGv_vec n) +{ +TCGv_vec t = tcg_temp_new_vec_matching(d); + +gen_saddlp_vec(vece, t, n); +tcg_gen_add_vec(vece, d, d, t); +} + +static void gen_sadalp_b_i64(TCGv_i64 d, TCGv_i64 n) +{ +TCGv_i64 t = tcg_temp_new_i64(); + +gen_helper_neon_addlp_s8(t, n); +tcg_gen_vec_add16_i64(d, d, t); +} + +static void gen_sadalp_h_i64(TCGv_i64 d, TCGv_i64 n) +{ +TCGv_i64 t = tcg_temp_new_i64(); + +gen_helper_neon_addlp_s16(t, n); +tcg_gen_vec_add32_i64(d, d, t); +} + +static void gen_sadalp_s_i64(TCGv_i64 d, TCGv_i64 n) +{ +TCGv_i64 t = tcg_temp_new_i64(); + +gen_saddlp_s_i64(t, n); +tcg_gen_add_i64(d, d, t); +} + +void gen_gvec_sadalp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, + uint32_t opr_sz, uint32_t max_sz) +{ +static const TCGOpcode vecop_list[] = { +INDEX_op_sari_vec, INDEX_op_shli_vec, INDEX_op_add_vec, 0 +}; +static const GVecGen2 g[] = { +{ .fniv = gen_sadalp_vec, + .fni8 = gen_sadalp_b_i64, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_16 }, +{ .fniv = gen_sadalp_vec, + .fni8 = gen_sadalp_h_i64, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_32 }, +{ .fniv = gen_sadalp_vec, + .fni8 = gen_sadalp_s_i64, + .opt
[PULL 42/49] rust: qom: rename Class trait to ClassInitImpl
While at it, document it. Signed-off-by: Paolo Bonzini --- rust/hw/char/pl011/src/device.rs | 4 ++-- rust/qemu-api/src/definitions.rs | 25 ++--- rust/qemu-api/tests/tests.rs | 4 ++-- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 3d173ae816d..bd12067aaf0 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -117,7 +117,7 @@ pub struct PL011Class { _inner: [u8; 0], } -impl qemu_api::definitions::Class for PL011Class { +impl qemu_api::definitions::ClassInitImpl for PL011Class { const CLASS_INIT: Option = Some(crate::device_class::pl011_class_init); const CLASS_BASE_INIT: Option< @@ -650,7 +650,7 @@ pub struct PL011LuminaryClass { } } -impl qemu_api::definitions::Class for PL011LuminaryClass { +impl qemu_api::definitions::ClassInitImpl for PL011LuminaryClass { const CLASS_INIT: Option = None; const CLASS_BASE_INIT: Option< diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs index 92b3c6f9118..3291f4242ce 100644 --- a/rust/qemu-api/src/definitions.rs +++ b/rust/qemu-api/src/definitions.rs @@ -20,8 +20,27 @@ pub trait ObjectImpl { const INSTANCE_FINALIZE: Option = None; } -pub trait Class { +/// Trait used to fill in a class struct. +/// +/// Each QOM class that has virtual methods describes them in a +/// _class struct_. Class structs include a parent field corresponding +/// to the vtable of the parent class, all the way up to [`ObjectClass`]. +/// Each QOM type has one such class struct. +/// +/// The Rust implementation of methods will usually come from a trait +/// like [`ObjectImpl`]. +pub trait ClassInitImpl { +/// Function that is called after all parent class initialization +/// has occurred. On entry, the virtual method pointers are set to +/// the default values coming from the parent classes; the function +/// can change them to override virtual methods of a parent class. const CLASS_INIT: Option; + +/// Called on descendent classes after all parent class initialization +/// has occurred, but before the class itself is initialized. This +/// is only useful if a class is not a leaf, and can be used to undo +/// the effects of copying the contents of the parent's class struct +/// to the descendants. const CLASS_BASE_INIT: Option< unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void), >; @@ -82,8 +101,8 @@ macro_rules! type_info { instance_finalize: <$t as $crate::definitions::ObjectImpl>::INSTANCE_FINALIZE, abstract_: <$t as $crate::definitions::ObjectImpl>::ABSTRACT, class_size: ::core::mem::size_of::<<$t as $crate::definitions::ObjectImpl>::Class>(), -class_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::Class>::CLASS_INIT, -class_base_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::Class>::CLASS_BASE_INIT, +class_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::ClassInitImpl>::CLASS_INIT, +class_base_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::ClassInitImpl>::CLASS_BASE_INIT, class_data: ::core::ptr::null_mut(), interfaces: ::core::ptr::null_mut(), }; diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs index f793ff26e5d..704c63c846f 100644 --- a/rust/qemu-api/tests/tests.rs +++ b/rust/qemu-api/tests/tests.rs @@ -7,7 +7,7 @@ use qemu_api::{ bindings::*, c_str, declare_properties, define_property, -definitions::{Class, ObjectImpl}, +definitions::{ClassInitImpl, ObjectImpl}, device_class, device_class_init, zeroable::Zeroable, }; @@ -60,7 +60,7 @@ impl ObjectImpl for DummyState { const PARENT_TYPE_NAME: Option<&'static CStr> = Some(device_class::TYPE_DEVICE); } -impl Class for DummyClass { +impl ClassInitImpl for DummyClass { const CLASS_INIT: Option = Some(dummy_class_init); const CLASS_BASE_INIT: Option< -- 2.47.1
[PATCH v3 47/69] target/arm: Remove helper_neon_{add,sub}l_u{16,32}
These have generic equivalents: tcg_gen_vec_{add,sub}{16,32}_i64. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/helper.h | 4 target/arm/tcg/neon_helper.c| 36 - target/arm/tcg/translate-neon.c | 22 ++-- 3 files changed, 11 insertions(+), 51 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 6369d07d05..04e422ab08 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -395,12 +395,8 @@ DEF_HELPER_1(neon_widen_s8, i64, i32) DEF_HELPER_1(neon_widen_u16, i64, i32) DEF_HELPER_1(neon_widen_s16, i64, i32) -DEF_HELPER_2(neon_addl_u16, i64, i64, i64) -DEF_HELPER_2(neon_addl_u32, i64, i64, i64) DEF_HELPER_FLAGS_1(neon_addlp_s8, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(neon_addlp_s16, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_2(neon_subl_u16, i64, i64, i64) -DEF_HELPER_2(neon_subl_u32, i64, i64, i64) DEF_HELPER_3(neon_addl_saturate_s32, i64, env, i64, i64) DEF_HELPER_3(neon_addl_saturate_s64, i64, env, i64, i64) DEF_HELPER_2(neon_abdl_u16, i64, i32, i32) diff --git a/target/arm/tcg/neon_helper.c b/target/arm/tcg/neon_helper.c index 1a22857b5e..c687e882ad 100644 --- a/target/arm/tcg/neon_helper.c +++ b/target/arm/tcg/neon_helper.c @@ -826,24 +826,6 @@ uint64_t HELPER(neon_widen_s16)(uint32_t x) return ((uint32_t)(int16_t)x) | (high << 32); } -uint64_t HELPER(neon_addl_u16)(uint64_t a, uint64_t b) -{ -uint64_t mask; -mask = (a ^ b) & 0x8000800080008000ull; -a &= ~0x8000800080008000ull; -b &= ~0x8000800080008000ull; -return (a + b) ^ mask; -} - -uint64_t HELPER(neon_addl_u32)(uint64_t a, uint64_t b) -{ -uint64_t mask; -mask = (a ^ b) & 0x80008000ull; -a &= ~0x80008000ull; -b &= ~0x80008000ull; -return (a + b) ^ mask; -} - /* Pairwise long add: add pairs of adjacent elements into * double-width elements in the result (eg _s8 is an 8x8->16 op) */ @@ -887,24 +869,6 @@ uint64_t HELPER(neon_addlp_s16)(uint64_t a) return (uint32_t)reslo | (((uint64_t)reshi) << 32); } -uint64_t HELPER(neon_subl_u16)(uint64_t a, uint64_t b) -{ -uint64_t mask; -mask = (a ^ ~b) & 0x8000800080008000ull; -a |= 0x8000800080008000ull; -b &= ~0x8000800080008000ull; -return (a - b) ^ mask; -} - -uint64_t HELPER(neon_subl_u32)(uint64_t a, uint64_t b) -{ -uint64_t mask; -mask = (a ^ ~b) & 0x80008000ull; -a |= 0x80008000ull; -b &= ~0x80008000ull; -return (a - b) ^ mask; -} - uint64_t HELPER(neon_addl_saturate_s32)(CPUARMState *env, uint64_t a, uint64_t b) { uint32_t x, y; diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c index 19a18018f1..0821f10fad 100644 --- a/target/arm/tcg/translate-neon.c +++ b/target/arm/tcg/translate-neon.c @@ -1560,8 +1560,8 @@ static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, NULL, NULL, \ }; \ static NeonGenTwo64OpFn * const addfn[] = { \ -gen_helper_neon_##OP##l_u16,\ -gen_helper_neon_##OP##l_u32,\ +tcg_gen_vec_##OP##16_i64, \ +tcg_gen_vec_##OP##32_i64, \ tcg_gen_##OP##_i64, \ NULL, \ }; \ @@ -1639,8 +1639,8 @@ static bool do_narrow_3d(DisasContext *s, arg_3diff *a, static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)\ { \ static NeonGenTwo64OpFn * const addfn[] = { \ -gen_helper_neon_##OP##l_u16,\ -gen_helper_neon_##OP##l_u32,\ +tcg_gen_vec_##OP##16_i64, \ +tcg_gen_vec_##OP##32_i64, \ tcg_gen_##OP##_i64, \ NULL, \ }; \ @@ -1761,8 +1761,8 @@ static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a) NULL, }; static NeonGenTwo64OpFn * const addfn[] = { -gen_helper_neon_addl_u16, -gen_helper_neon_addl_u32, +tcg_gen_vec_add16_i64, +tcg_gen_vec_add32_i64, tcg_gen_add_i64, NULL, }; @@ -1779,8 +1779,8 @@ static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) NULL, }; static NeonGenTwo64OpFn *
[PATCH v3 48/69] target/arm: Introduce clear_vec
In a couple of places, clearing the entire vector before storing one element is the easiest solution. Wrap that into a helper function. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 21 - 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 717d30dd5b..0e8e867058 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -628,7 +628,16 @@ static TCGv_i32 read_fp_hreg(DisasContext *s, int reg) return v; } -/* Clear the bits above an N-bit vector, for N = (is_q ? 128 : 64). +static void clear_vec(DisasContext *s, int rd) +{ +unsigned ofs = fp_reg_offset(s, rd, MO_64); +unsigned vsz = vec_full_reg_size(s); + +tcg_gen_gvec_dup_imm(MO_64, ofs, vsz, vsz, 0); +} + +/* + * Clear the bits above an N-bit vector, for N = (is_q ? 128 : 64). * If SVE is not enabled, then there are only 128 bits in the vector. */ static void clear_vec_high(DisasContext *s, bool is_q, int rd) @@ -4851,7 +4860,6 @@ static bool trans_SM3SS1(DisasContext *s, arg_SM3SS1 *a) TCGv_i32 tcg_op2 = tcg_temp_new_i32(); TCGv_i32 tcg_op3 = tcg_temp_new_i32(); TCGv_i32 tcg_res = tcg_temp_new_i32(); -unsigned vsz, dofs; read_vec_element_i32(s, tcg_op1, a->rn, 3, MO_32); read_vec_element_i32(s, tcg_op2, a->rm, 3, MO_32); @@ -4863,9 +4871,7 @@ static bool trans_SM3SS1(DisasContext *s, arg_SM3SS1 *a) tcg_gen_rotri_i32(tcg_res, tcg_res, 25); /* Clear the whole register first, then store bits [127:96]. */ -vsz = vec_full_reg_size(s); -dofs = vec_full_reg_offset(s, a->rd); -tcg_gen_gvec_dup_imm(MO_64, dofs, vsz, vsz, 0); +clear_vec(s, a->rd); write_vec_element_i32(s, tcg_res, a->rd, 3, MO_32); } return true; @@ -6307,7 +6313,6 @@ static bool do_scalar_muladd_widening_idx(DisasContext *s, arg_rrx_e *a, TCGv_i64 t0 = tcg_temp_new_i64(); TCGv_i64 t1 = tcg_temp_new_i64(); TCGv_i64 t2 = tcg_temp_new_i64(); -unsigned vsz, dofs; if (acc) { read_vec_element(s, t0, a->rd, 0, a->esz + 1); @@ -6317,9 +6322,7 @@ static bool do_scalar_muladd_widening_idx(DisasContext *s, arg_rrx_e *a, fn(t0, t1, t2); /* Clear the whole register first, then store scalar. */ -vsz = vec_full_reg_size(s); -dofs = vec_full_reg_offset(s, a->rd); -tcg_gen_gvec_dup_imm(MO_64, dofs, vsz, vsz, 0); +clear_vec(s, a->rd); write_vec_element(s, t0, a->rd, 0, a->esz + 1); } return true; -- 2.43.0
[PATCH v3 07/69] target/arm: Convert RBIT, REV16, REV32, REV64 to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 137 +++-- target/arm/tcg/a64.decode | 11 +++ 2 files changed, 72 insertions(+), 76 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index ca8b644dc7..1805d77f43 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -7684,6 +7684,60 @@ static bool trans_PACGA(DisasContext *s, arg_rrr *a) return false; } +typedef void ArithOneOp(TCGv_i64, TCGv_i64); + +static bool gen_rr(DisasContext *s, int rd, int rn, ArithOneOp fn) +{ +fn(cpu_reg(s, rd), cpu_reg(s, rn)); +return true; +} + +static void gen_rbit32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn) +{ +TCGv_i32 t32 = tcg_temp_new_i32(); + +tcg_gen_extrl_i64_i32(t32, tcg_rn); +gen_helper_rbit(t32, t32); +tcg_gen_extu_i32_i64(tcg_rd, t32); +} + +static void gen_rev16_xx(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn, TCGv_i64 mask) +{ +TCGv_i64 tcg_tmp = tcg_temp_new_i64(); + +tcg_gen_shri_i64(tcg_tmp, tcg_rn, 8); +tcg_gen_and_i64(tcg_rd, tcg_rn, mask); +tcg_gen_and_i64(tcg_tmp, tcg_tmp, mask); +tcg_gen_shli_i64(tcg_rd, tcg_rd, 8); +tcg_gen_or_i64(tcg_rd, tcg_rd, tcg_tmp); +} + +static void gen_rev16_32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn) +{ +gen_rev16_xx(tcg_rd, tcg_rn, tcg_constant_i64(0x00ff00ff)); +} + +static void gen_rev16_64(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn) +{ +gen_rev16_xx(tcg_rd, tcg_rn, tcg_constant_i64(0x00ff00ff00ff00ffull)); +} + +static void gen_rev_32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn) +{ +tcg_gen_bswap32_i64(tcg_rd, tcg_rn, TCG_BSWAP_OZ); +} + +static void gen_rev32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn) +{ +tcg_gen_bswap64_i64(tcg_rd, tcg_rn); +tcg_gen_rotri_i64(tcg_rd, tcg_rd, 32); +} + +TRANS(RBIT, gen_rr, a->rd, a->rn, a->sf ? gen_helper_rbit64 : gen_rbit32) +TRANS(REV16, gen_rr, a->rd, a->rn, a->sf ? gen_rev16_64 : gen_rev16_32) +TRANS(REV32, gen_rr, a->rd, a->rn, a->sf ? gen_rev32 : gen_rev_32) +TRANS(REV64, gen_rr, a->rd, a->rn, tcg_gen_bswap64_i64) + /* Logical (shifted register) * 31 30 29 28 24 23 22 21 20 16 1510 95 40 * ++-+---+---+---+--++--+--+ @@ -8302,67 +8356,6 @@ static void handle_cls(DisasContext *s, unsigned int sf, } } -static void handle_rbit(DisasContext *s, unsigned int sf, -unsigned int rn, unsigned int rd) -{ -TCGv_i64 tcg_rd, tcg_rn; -tcg_rd = cpu_reg(s, rd); -tcg_rn = cpu_reg(s, rn); - -if (sf) { -gen_helper_rbit64(tcg_rd, tcg_rn); -} else { -TCGv_i32 tcg_tmp32 = tcg_temp_new_i32(); -tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn); -gen_helper_rbit(tcg_tmp32, tcg_tmp32); -tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32); -} -} - -/* REV with sf==1, opcode==3 ("REV64") */ -static void handle_rev64(DisasContext *s, unsigned int sf, - unsigned int rn, unsigned int rd) -{ -if (!sf) { -unallocated_encoding(s); -return; -} -tcg_gen_bswap64_i64(cpu_reg(s, rd), cpu_reg(s, rn)); -} - -/* REV with sf==0, opcode==2 - * REV32 (sf==1, opcode==2) - */ -static void handle_rev32(DisasContext *s, unsigned int sf, - unsigned int rn, unsigned int rd) -{ -TCGv_i64 tcg_rd = cpu_reg(s, rd); -TCGv_i64 tcg_rn = cpu_reg(s, rn); - -if (sf) { -tcg_gen_bswap64_i64(tcg_rd, tcg_rn); -tcg_gen_rotri_i64(tcg_rd, tcg_rd, 32); -} else { -tcg_gen_bswap32_i64(tcg_rd, tcg_rn, TCG_BSWAP_OZ); -} -} - -/* REV16 (opcode==1) */ -static void handle_rev16(DisasContext *s, unsigned int sf, - unsigned int rn, unsigned int rd) -{ -TCGv_i64 tcg_rd = cpu_reg(s, rd); -TCGv_i64 tcg_tmp = tcg_temp_new_i64(); -TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf); -TCGv_i64 mask = tcg_constant_i64(sf ? 0x00ff00ff00ff00ffull : 0x00ff00ff); - -tcg_gen_shri_i64(tcg_tmp, tcg_rn, 8); -tcg_gen_and_i64(tcg_rd, tcg_rn, mask); -tcg_gen_and_i64(tcg_tmp, tcg_tmp, mask); -tcg_gen_shli_i64(tcg_rd, tcg_rd, 8); -tcg_gen_or_i64(tcg_rd, tcg_rd, tcg_tmp); -} - /* Data-processing (1 source) * 31 30 29 28 21 20 16 1510 95 40 * ++---+---+-+-++--+--+ @@ -8388,21 +8381,6 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn) #define MAP(SF, O2, O1) ((SF) | (O1 << 1) | (O2 << 7)) switch (MAP(sf, opcode2, opcode)) { -case MAP(0, 0x00, 0x00): /* RBIT */ -case MAP(1, 0x00, 0x00): -handle_rbit(s, sf, rn, rd); -break; -case MAP(0, 0x00, 0x01): /* REV16 */ -case MAP(1, 0x00, 0x01): -handle_rev16(s, sf, rn, rd); -break; -case MAP(0, 0x00, 0x02): /* REV/REV32 */ -case MAP(1, 0x00, 0x02): -handle_rev32(s, sf, rn, rd); -break; -case MAP(1, 0x00, 0x03): /* REV64 */ -
[PULL 48/49] rust: qom: split ObjectType from ObjectImpl trait
Define a separate trait for fields that also applies to classes that are defined by C code. This makes it possible to add metadata to core classes, which has multiple uses: - it makes it possible to access the parent struct's TYPE_* for types that are defined in Rust code, and to avoid repeating it in every subclass - implementors of ObjectType will be allowed to implement the IsA<> trait and therefore to perform typesafe casts from one class to another. - in the future, an ObjectType could be created with Foo::new() in a type-safe manner, without having to pass a TYPE_* constant. Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/hw/char/pl011/src/device.rs | 17 - rust/qemu-api/src/definitions.rs | 27 +-- rust/qemu-api/src/device_class.rs | 11 ++- rust/qemu-api/src/prelude.rs | 2 ++ rust/qemu-api/src/sysbus.rs | 10 -- rust/qemu-api/tests/tests.rs | 17 + 6 files changed, 58 insertions(+), 26 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index b9f8fb134b5..0ab825b1ca4 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -12,9 +12,10 @@ bindings::{self, *}, c_str, definitions::ObjectImpl, -device_class::{DeviceImpl, TYPE_SYS_BUS_DEVICE}, +device_class::DeviceImpl, impl_device_class, irq::InterruptSource, +prelude::*, }; use crate::{ @@ -106,10 +107,13 @@ pub struct PL011State { device_id: DeviceId, } -impl ObjectImpl for PL011State { +unsafe impl ObjectType for PL011State { type Class = PL011Class; const TYPE_NAME: &'static CStr = crate::TYPE_PL011; -const PARENT_TYPE_NAME: Option<&'static CStr> = Some(TYPE_SYS_BUS_DEVICE); +} + +impl ObjectImpl for PL011State { +const PARENT_TYPE_NAME: Option<&'static CStr> = Some(::TYPE_NAME); const INSTANCE_INIT: Option = Some(Self::init); } @@ -640,10 +644,13 @@ unsafe fn init(&mut self) { } } -impl ObjectImpl for PL011Luminary { +unsafe impl ObjectType for PL011Luminary { type Class = PL011LuminaryClass; const TYPE_NAME: &'static CStr = crate::TYPE_PL011_LUMINARY; -const PARENT_TYPE_NAME: Option<&'static CStr> = Some(crate::TYPE_PL011); +} + +impl ObjectImpl for PL011Luminary { +const PARENT_TYPE_NAME: Option<&'static CStr> = Some(::TYPE_NAME); const INSTANCE_INIT: Option = Some(Self::init); } diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs index f2970758986..b98a6926785 100644 --- a/rust/qemu-api/src/definitions.rs +++ b/rust/qemu-api/src/definitions.rs @@ -26,25 +26,40 @@ T::INSTANCE_POST_INIT.unwrap()(unsafe { &mut *obj.cast::() }) } -/// Trait a type must implement to be registered with QEMU. +/// Trait exposed by all structs corresponding to QOM objects. /// /// # Safety /// -/// - the struct must be `#[repr(C)]` +/// For classes declared in C: /// -/// - `Class` and `TYPE` must match the data in the `TypeInfo` (this is -/// automatic if the class is defined via `ObjectImpl`). +/// - `Class` and `TYPE` must match the data in the `TypeInfo`; +/// +/// - the first field of the struct must be of the instance type corresponding +/// to the superclass, as declared in the `TypeInfo` +/// +/// - likewise, the first field of the `Class` struct must be of the class type +/// corresponding to the superclass +/// +/// For classes declared in Rust and implementing [`ObjectImpl`]: +/// +/// - the struct must be `#[repr(C)]`; /// /// - the first field of the struct must be of the instance struct corresponding -/// to the superclass declared as `PARENT_TYPE_NAME` -pub trait ObjectImpl: ClassInitImpl + Sized { +/// to the superclass, as declared in `ObjectImpl::PARENT_TYPE_NAME` +/// +/// - likewise, the first field of the `Class` must be of the class struct +/// corresponding to the superclass +pub unsafe trait ObjectType: Sized { /// The QOM class object corresponding to this struct. Not used yet. type Class; /// The name of the type, which can be passed to `object_new()` to /// generate an instance of this type. const TYPE_NAME: &'static CStr; +} +/// Trait a type must implement to be registered with QEMU. +pub trait ObjectImpl: ObjectType + ClassInitImpl { /// The parent of the type. This should match the first field of /// the struct that implements `ObjectImpl`: const PARENT_TYPE_NAME: Option<&'static CStr>; diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs index f25904be4f6..03d03feee83 100644 --- a/rust/qemu-api/src/device_class.rs +++ b/rust/qemu-api/src/device_class.rs @@ -6,6 +6,7 @@ use crate::{ bindings::{self, DeviceClass, DeviceState, Error, ObjectClass, Property, VMStateDescription}, +prelude::*, zeroable::Zeroable, }; @@ -146,8 +147,8 @@ macro_rules! declare_properties { }; } -// workaround
[PULL 46/49] rust: qdev: move bridge for realize and reset functions out of pl011
Allow the DeviceImpl trait to expose safe Rust functions. rust_device_class_init<> adds thunks around the functions in DeviceImpl. Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/hw/char/pl011/src/device.rs | 5 ++-- rust/hw/char/pl011/src/device_class.rs | 26 --- rust/qemu-api/src/definitions.rs | 2 +- rust/qemu-api/src/device_class.rs | 36 +- 4 files changed, 33 insertions(+), 36 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 28b1924337d..56403c36609 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -125,9 +125,8 @@ fn properties() -> &'static [Property] { fn vmsd() -> Option<&'static VMStateDescription> { Some(&device_class::VMSTATE_PL011) } -const REALIZE: Option = -Some(device_class::pl011_realize); -const RESET: Option = Some(device_class::pl011_reset); +const REALIZE: Option = Some(Self::realize); +const RESET: Option = Some(Self::reset); } impl_device_class!(PL011State); diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs index c61b6bb0258..975c3d42be7 100644 --- a/rust/hw/char/pl011/src/device_class.rs +++ b/rust/hw/char/pl011/src/device_class.rs @@ -92,29 +92,3 @@ extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int { default = true ), } - -/// # Safety -/// -/// We expect the FFI user of this function to pass a valid pointer, that has -/// the same size as [`PL011State`]. We also expect the device is -/// readable/writeable from one thread at any time. -pub unsafe extern "C" fn pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error) { -unsafe { -assert!(!dev.is_null()); -let mut state = NonNull::new_unchecked(dev.cast::()); -state.as_mut().realize(); -} -} - -/// # Safety -/// -/// We expect the FFI user of this function to pass a valid pointer, that has -/// the same size as [`PL011State`]. We also expect the device is -/// readable/writeable from one thread at any time. -pub unsafe extern "C" fn pl011_reset(dev: *mut DeviceState) { -unsafe { -assert!(!dev.is_null()); -let mut state = NonNull::new_unchecked(dev.cast::()); -state.as_mut().reset(); -} -} diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs index 487712611f6..0467e6290e0 100644 --- a/rust/qemu-api/src/definitions.rs +++ b/rust/qemu-api/src/definitions.rs @@ -47,7 +47,7 @@ pub trait ObjectImpl: ClassInitImpl + Sized { /// Each QOM type has one such class struct. /// /// The Rust implementation of methods will usually come from a trait -/// like [`ObjectImpl`]. +/// like [`ObjectImpl`] or [`DeviceImpl`](crate::device_class::DeviceImpl). pub trait ClassInitImpl { /// Function that is called after all parent class initialization /// has occurred. On entry, the virtual method pointers are set to diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs index f683f94f2a5..f25904be4f6 100644 --- a/rust/qemu-api/src/device_class.rs +++ b/rust/qemu-api/src/device_class.rs @@ -17,14 +17,14 @@ pub trait DeviceImpl { /// /// If not `None`, the parent class's `realize` method is overridden /// with the function pointed to by `REALIZE`. -const REALIZE: Option = None; +const REALIZE: Option = None; /// If not `None`, the parent class's `reset` method is overridden /// with the function pointed to by `RESET`. /// /// Rust does not yet support the three-phase reset protocol; this is /// usually okay for leaf classes. -const RESET: Option = None; +const RESET: Option = None; /// An array providing the properties that the user can set on the /// device. Not a `const` because referencing statics in constants @@ -41,6 +41,30 @@ fn vmsd() -> Option<&'static VMStateDescription> { } } +/// # Safety +/// +/// This function is only called through the QOM machinery and +/// the `impl_device_class!` macro. +/// We expect the FFI user of this function to pass a valid pointer that +/// can be downcasted to type `T`. We also expect the device is +/// readable/writeable from one thread at any time. +unsafe extern "C" fn rust_realize_fn(dev: *mut DeviceState, _errp: *mut *mut Error) { +assert!(!dev.is_null()); +let state = dev.cast::(); +T::REALIZE.unwrap()(unsafe { &mut *state }); +} + +/// # Safety +/// +/// We expect the FFI user of this function to pass a valid pointer that +/// can be downcasted to type `T`. We also expect the device is +/// readable/writeable from one thread at any time. +unsafe extern "C" fn rust_reset_fn(dev: *mut DeviceState) { +assert!(!dev.is_null()); +let state = dev.cast::(); +T::RESET.unwrap()(unsafe { &mut *state }); +} + /// # Safety /// /// We expect the FFI user of this function to pass a va
[PATCH v2 27/31] tests/functional: drop back compat imports from utils.py
Now that all tests are converted over to the higher level wrapper functions, the back compat imports from utils.py are redundant. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/utils.py | 5 - 1 file changed, 5 deletions(-) diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py index 6b87af4414..43853b4366 100644 --- a/tests/functional/qemu_test/utils.py +++ b/tests/functional/qemu_test/utils.py @@ -10,11 +10,6 @@ import os -from .archive import tar_extract as archive_extract -from .archive import cpio_extract -from .uncompress import gzip_uncompress -from .uncompress import lzma_uncompress - """ Round up to next power of 2 """ -- 2.46.0
[PULL 38/49] rust: define prelude
Add a module that will contain frequently used traits and occasionally structs. They can be included quickly with "use qemu_api::prelude::*". Signed-off-by: Paolo Bonzini --- rust/qemu-api/meson.build| 1 + rust/qemu-api/src/lib.rs | 5 + rust/qemu-api/src/prelude.rs | 6 ++ 3 files changed, 12 insertions(+) create mode 100644 rust/qemu-api/src/prelude.rs diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index cacb112c5c3..f8b4cd39a26 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -21,6 +21,7 @@ _qemu_api_rs = static_library( 'src/definitions.rs', 'src/device_class.rs', 'src/offset_of.rs', + 'src/prelude.rs', 'src/vmstate.rs', 'src/zeroable.rs', ], diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs index b04d110b3f5..e5956cd5eb6 100644 --- a/rust/qemu-api/src/lib.rs +++ b/rust/qemu-api/src/lib.rs @@ -7,6 +7,11 @@ #[rustfmt::skip] pub mod bindings; +// preserve one-item-per-"use" syntax, it is clearer +// for prelude-like modules +#[rustfmt::skip] +pub mod prelude; + pub mod c_str; pub mod cell; pub mod definitions; diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs new file mode 100644 index 000..dfaddbd062a --- /dev/null +++ b/rust/qemu-api/src/prelude.rs @@ -0,0 +1,6 @@ +// Copyright 2024 Red Hat, Inc. +// Author(s): Paolo Bonzini +// SPDX-License-Identifier: GPL-2.0-or-later + +pub use crate::cell::BqlCell; +pub use crate::cell::BqlRefCell; -- 2.47.1
[PATCH v3 55/69] target/arm: Convert FSQRT (vector) to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 69 -- target/arm/tcg/a64.decode | 3 ++ 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index fd7f7ae714..287e9338a4 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -9164,6 +9164,51 @@ static bool do_fabs_fneg_v(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) TRANS(FABS_v, do_fabs_fneg_v, a, gen_gvec_fabs) TRANS(FNEG_v, do_fabs_fneg_v, a, gen_gvec_fneg) +static bool do_fp1_vector(DisasContext *s, arg_qrr_e *a, + const FPScalar1 *f, int rmode) +{ +TCGv_i32 tcg_rmode = NULL; +TCGv_ptr fpst; +int check = fp_access_check_vector_hsd(s, a->q, a->esz); + +if (check <= 0) { +return check == 0; +} + +fpst = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); +if (rmode >= 0) { +tcg_rmode = gen_set_rmode(rmode, fpst); +} + +if (a->esz == MO_64) { +TCGv_i64 t64 = tcg_temp_new_i64(); + +for (int pass = 0; pass < 2; ++pass) { +read_vec_element(s, t64, a->rn, pass, MO_64); +f->gen_d(t64, t64, fpst); +write_vec_element(s, t64, a->rd, pass, MO_64); +} +} else { +TCGv_i32 t32 = tcg_temp_new_i32(); +void (*gen)(TCGv_i32, TCGv_i32, TCGv_ptr) += (a->esz == MO_16 ? f->gen_h : f->gen_s); + +for (int pass = 0, n = (a->q ? 16 : 8) >> a->esz; pass < n; ++pass) { +read_vec_element_i32(s, t32, a->rn, pass, a->esz); +gen(t32, t32, fpst); +write_vec_element_i32(s, t32, a->rd, pass, a->esz); +} +} +clear_vec_high(s, a->q, a->rd); + +if (rmode >= 0) { +gen_restore_rmode(tcg_rmode, fpst); +} +return true; +} + +TRANS(FSQRT_v, do_fp1_vector, a, &f_scalar_fsqrt, -1) + /* Common vector code for handling integer to FP conversion */ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, int elements, int is_signed, @@ -9461,9 +9506,6 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, * requires them. */ switch (opcode) { -case 0x7f: /* FSQRT */ -gen_helper_vfp_sqrtd(tcg_rd, tcg_rn, tcg_fpstatus); -break; case 0x1a: /* FCVTNS */ case 0x1b: /* FCVTMS */ case 0x1c: /* FCVTAS */ @@ -9507,6 +9549,7 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, case 0xb: /* ABS, NEG */ case 0x2f: /* FABS */ case 0x6f: /* FNEG */ +case 0x7f: /* FSQRT */ g_assert_not_reached(); } } @@ -10004,13 +10047,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) } handle_2misc_fcmp_zero(s, opcode, false, u, is_q, size, rn, rd); return; -case 0x7f: /* FSQRT */ -need_fpstatus = true; -if (size == 3 && !is_q) { -unallocated_encoding(s); -return; -} -break; case 0x1a: /* FCVTNS */ case 0x1b: /* FCVTMS */ case 0x3a: /* FCVTPS */ @@ -10104,6 +10140,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) case 0x56: /* FCVTXN, FCVTXN2 */ case 0x2f: /* FABS */ case 0x6f: /* FNEG */ +case 0x7f: /* FSQRT */ unallocated_encoding(s); return; } @@ -10176,9 +10213,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) { /* Special cases for 32 bit elements */ switch (opcode) { -case 0x7f: /* FSQRT */ -gen_helper_vfp_sqrts(tcg_res, tcg_op, tcg_fpstatus); -break; case 0x1a: /* FCVTNS */ case 0x1b: /* FCVTMS */ case 0x1c: /* FCVTAS */ @@ -10221,6 +10255,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) case 0x7: /* SQABS, SQNEG */ case 0x2f: /* FABS */ case 0x6f: /* FNEG */ +case 0x7f: /* FSQRT */ g_assert_not_reached(); } } @@ -10365,12 +10400,10 @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) break; case 0x7d: /* FRSQRTE */ break; -case 0x7f: /* FSQRT (vector) */ -only_in_vector = true; -break; default: case 0x2f: /* FABS */ case 0x6f: /* FNEG */ +case 0x7f: /* FSQRT (vector) */ unallocated_encoding(s); return; } @@ -10475,12 +10508,10 @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) case 0x7d: /* FRSQRTE */ gen_helper_rsqrte_f16(tcg_res, tcg_op, tcg_fpstatus);
[PATCH v3 38/69] target/arm: Convert CLS, CLZ (vector) to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 37 -- target/arm/tcg/a64.decode | 2 ++ 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 387bbbf906..ecb4578998 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8916,6 +8916,20 @@ static bool do_gvec_fn2(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) TRANS(ABS_v, do_gvec_fn2, a, tcg_gen_gvec_abs) TRANS(NEG_v, do_gvec_fn2, a, tcg_gen_gvec_neg) +static bool do_gvec_fn2_bhs(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) +{ +if (a->esz == MO_64) { +return false; +} +if (fp_access_check(s)) { +gen_gvec_fn2(s, a->q, a->rd, a->rn, fn, a->esz); +} +return true; +} + +TRANS(CLS_v, do_gvec_fn2_bhs, a, gen_gvec_cls) +TRANS(CLZ_v, do_gvec_fn2_bhs, a, gen_gvec_clz) + /* Common vector code for handling integer to FP conversion */ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, int elements, int is_signed, @@ -9215,13 +9229,6 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, TCGCond cond; switch (opcode) { -case 0x4: /* CLS, CLZ */ -if (u) { -tcg_gen_clzi_i64(tcg_rd, tcg_rn, 64); -} else { -tcg_gen_clrsb_i64(tcg_rd, tcg_rn); -} -break; case 0x5: /* NOT */ /* This opcode is shared with CNT and RBIT but we have earlier * enforced that size == 3 if and only if this is the NOT insn. @@ -9283,6 +9290,7 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, gen_helper_frint64_d(tcg_rd, tcg_rn, tcg_fpstatus); break; default: +case 0x4: /* CLS, CLZ */ case 0x7: /* SQABS, SQNEG */ case 0xb: /* ABS, NEG */ g_assert_not_reached(); @@ -10089,12 +10097,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) handle_2misc_narrow(s, false, opcode, u, is_q, size, rn, rd); return; -case 0x4: /* CLS, CLZ */ -if (size == 3) { -unallocated_encoding(s); -return; -} -break; case 0x2: /* SADDLP, UADDLP */ case 0x6: /* SADALP, UADALP */ if (size == 3) { @@ -10299,6 +10301,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) } default: case 0x3: /* SUQADD, USQADD */ +case 0x4: /* CLS, CLZ */ case 0x7: /* SQABS, SQNEG */ case 0xb: /* ABS, NEG */ unallocated_encoding(s); @@ -10321,13 +10324,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) } switch (opcode) { -case 0x4: /* CLZ, CLS */ -if (u) { -gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_clz, size); -} else { -gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cls, size); -} -return; case 0x5: if (u && size == 0) { /* NOT */ gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_not, 0); @@ -10351,6 +10347,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) case 0xa: /* CMLT */ gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_clt0, size); return; +case 0x4: /* CLZ, CLS */ case 0xb: g_assert_not_reached(); } diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index f112951df7..32355ee633 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -1641,3 +1641,5 @@ SQABS_v 0.00 1110 ..1 0 0 0 . . @qrr_e SQNEG_v 0.10 1110 ..1 0 0 0 . . @qrr_e ABS_v 0.00 1110 ..1 0 10111 0 . . @qrr_e NEG_v 0.10 1110 ..1 0 10111 0 . . @qrr_e +CLS_v 0.00 1110 ..1 0 01001 0 . . @qrr_e +CLZ_v 0.10 1110 ..1 0 01001 0 . . @qrr_e -- 2.43.0
[PATCH v3 18/69] target/arm: Convert CCMP, CCMN to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 66 +++--- target/arm/tcg/a64.decode | 6 ++-- 2 files changed, 25 insertions(+), 47 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 774689641d..56a445a3c2 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8092,68 +8092,46 @@ static bool do_setf(DisasContext *s, int rn, int shift) TRANS_FEAT(SETF8, aa64_condm_4, do_setf, a->rn, 24) TRANS_FEAT(SETF16, aa64_condm_4, do_setf, a->rn, 16) -/* Conditional compare (immediate / register) - * 31 30 29 28 27 26 25 24 23 22 21 2016 15 12 11 10 9 5 4 3 0 - * +--+--+--+++--++--+--+--+-+ - * |sf|op| S| 1 1 0 1 0 0 1 0 |imm5/rm | cond |i/r |o2| Rn |o3|nzcv | - * +--+--+--+++--++--+--+--+-+ - *[1] y[0] [0] - */ -static void disas_cc(DisasContext *s, uint32_t insn) +/* CCMP, CCMN */ +static bool trans_CCMP(DisasContext *s, arg_CCMP *a) { -unsigned int sf, op, y, cond, rn, nzcv, is_imm; -TCGv_i32 tcg_t0, tcg_t1, tcg_t2; -TCGv_i64 tcg_tmp, tcg_y, tcg_rn; +TCGv_i32 tcg_t0 = tcg_temp_new_i32(); +TCGv_i32 tcg_t1 = tcg_temp_new_i32(); +TCGv_i32 tcg_t2 = tcg_temp_new_i32(); +TCGv_i64 tcg_tmp = tcg_temp_new_i64(); +TCGv_i64 tcg_rn, tcg_y; DisasCompare c; - -if (!extract32(insn, 29, 1)) { -unallocated_encoding(s); -return; -} -if (insn & (1 << 10 | 1 << 4)) { -unallocated_encoding(s); -return; -} -sf = extract32(insn, 31, 1); -op = extract32(insn, 30, 1); -is_imm = extract32(insn, 11, 1); -y = extract32(insn, 16, 5); /* y = rm (reg) or imm5 (imm) */ -cond = extract32(insn, 12, 4); -rn = extract32(insn, 5, 5); -nzcv = extract32(insn, 0, 4); +unsigned nzcv; /* Set T0 = !COND. */ -tcg_t0 = tcg_temp_new_i32(); -arm_test_cc(&c, cond); +arm_test_cc(&c, a->cond); tcg_gen_setcondi_i32(tcg_invert_cond(c.cond), tcg_t0, c.value, 0); /* Load the arguments for the new comparison. */ -if (is_imm) { -tcg_y = tcg_temp_new_i64(); -tcg_gen_movi_i64(tcg_y, y); +if (a->imm) { +tcg_y = tcg_constant_i64(a->y); } else { -tcg_y = cpu_reg(s, y); +tcg_y = cpu_reg(s, a->y); } -tcg_rn = cpu_reg(s, rn); +tcg_rn = cpu_reg(s, a->rn); /* Set the flags for the new comparison. */ -tcg_tmp = tcg_temp_new_i64(); -if (op) { -gen_sub_CC(sf, tcg_tmp, tcg_rn, tcg_y); +if (a->op) { +gen_sub_CC(a->sf, tcg_tmp, tcg_rn, tcg_y); } else { -gen_add_CC(sf, tcg_tmp, tcg_rn, tcg_y); +gen_add_CC(a->sf, tcg_tmp, tcg_rn, tcg_y); } -/* If COND was false, force the flags to #nzcv. Compute two masks +/* + * If COND was false, force the flags to #nzcv. Compute two masks * to help with this: T1 = (COND ? 0 : -1), T2 = (COND ? -1 : 0). * For tcg hosts that support ANDC, we can make do with just T1. * In either case, allow the tcg optimizer to delete any unused mask. */ -tcg_t1 = tcg_temp_new_i32(); -tcg_t2 = tcg_temp_new_i32(); tcg_gen_neg_i32(tcg_t1, tcg_t0); tcg_gen_subi_i32(tcg_t2, tcg_t0, 1); +nzcv = a->nzcv; if (nzcv & 8) { /* N */ tcg_gen_or_i32(cpu_NF, cpu_NF, tcg_t1); } else { @@ -8190,6 +8168,7 @@ static void disas_cc(DisasContext *s, uint32_t insn) tcg_gen_and_i32(cpu_VF, cpu_VF, tcg_t2); } } +return true; } /* Conditional select @@ -8266,10 +8245,6 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) } switch (op2) { -case 0x2: /* Conditional compare */ -disas_cc(s, insn); /* both imm and reg forms */ -break; - case 0x4: /* Conditional select */ disas_cond_select(s, insn); break; @@ -8277,6 +8252,7 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) default: do_unallocated: case 0x0: +case 0x2: /* Conditional compare */ case 0x6: /* Data-processing */ case 0x8 ... 0xf: /* (3 source) */ unallocated_encoding(s); diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index ae2c6831d7..a9d7d57199 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -761,8 +761,10 @@ RMIF1 01 1101 imm:6 1 rn:5 0 mask:4 SETF8 0 01 1101 0 10 rn:5 01101 SETF16 0 01 1101 0 010010 rn:5 01101 -# Conditional compare (regster) -# Conditional compare (immediate) +# Conditional compare + +CCMPsf:1 op:1 1 11010010 y:5 cond:4 imm:1 0 rn:5 0 nzcv:4 + # Conditional select # Data Processing (3-source) -- 2.43.0
[PULL 35/49] bql: check that the BQL is not dropped within marked sections
The Big QEMU Lock (BQL) is used to provide interior mutability to Rust code. While BqlCell performs indivisible accesses, an equivalent of RefCell will allow the borrower to hold to the interior content for a long time. If the BQL is dropped, another thread could come and mutate the data from C code (Rust code would panic on borrow_mut() instead). In order to prevent this, add a new BQL primitive that can mark BQL-atomic sections and aborts if the BQL is dropped within them. Signed-off-by: Paolo Bonzini --- include/qemu/main-loop.h | 15 +++ stubs/iothread-lock.c| 15 +++ system/cpus.c| 15 +++ 3 files changed, 45 insertions(+) diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index 5764db157c9..646306c272f 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -262,6 +262,21 @@ AioContext *iohandler_get_aio_context(void); */ bool bql_locked(void); +/** + * bql_block: Allow/deny releasing the BQL + * + * The Big QEMU Lock (BQL) is used to provide interior mutability to + * Rust code, but this only works if other threads cannot run while + * the Rust code has an active borrow. This is because C code in + * other threads could come in and mutate data under the Rust code's + * feet. + * + * @increase: Whether to increase or decrease the blocking counter. + *Releasing the BQL while the counter is nonzero triggers + *an assertion failure. + */ +void bql_block_unlock(bool increase); + /** * qemu_in_main_thread: return whether it's possible to safely access * the global state of the block layer. diff --git a/stubs/iothread-lock.c b/stubs/iothread-lock.c index d7890e5581c..54676598950 100644 --- a/stubs/iothread-lock.c +++ b/stubs/iothread-lock.c @@ -1,6 +1,8 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" +static uint32_t bql_unlock_blocked; + bool bql_locked(void) { return false; @@ -12,4 +14,17 @@ void bql_lock_impl(const char *file, int line) void bql_unlock(void) { +assert(!bql_unlock_blocked); +} + +void bql_block_unlock(bool increase) +{ +uint32_t new_value; + +assert(bql_locked()); + +/* check for overflow! */ +new_value = bql_unlock_blocked + increase - !increase; +assert((new_value > bql_unlock_blocked) == increase); +bql_unlock_blocked = new_value; } diff --git a/system/cpus.c b/system/cpus.c index 1c818ff6828..ba633c7688b 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -514,6 +514,20 @@ bool qemu_in_vcpu_thread(void) QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked) +static uint32_t bql_unlock_blocked; + +void bql_block_unlock(bool increase) +{ +uint32_t new_value; + +assert(bql_locked()); + +/* check for overflow! */ +new_value = bql_unlock_blocked + increase - !increase; +assert((new_value > bql_unlock_blocked) == increase); +bql_unlock_blocked = new_value; +} + bool bql_locked(void) { return get_bql_locked(); @@ -540,6 +554,7 @@ void bql_lock_impl(const char *file, int line) void bql_unlock(void) { g_assert(bql_locked()); +g_assert(!bql_unlock_blocked); set_bql_locked(false); qemu_mutex_unlock(&bql); } -- 2.47.1
[PATCH v3 61/69] target/arm: Rename helper_gvec_vcvt_[hf][su] with _rz
Emphasize that these functions use round-to-zero mode. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/helper.h | 8 target/arm/tcg/translate-neon.c | 8 target/arm/tcg/vec_helper.c | 8 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 04e422ab08..f2cfee40de 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -650,13 +650,13 @@ DEF_HELPER_FLAGS_4(gvec_touizs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_vcvt_sf, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_vcvt_uf, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_fs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_fu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rz_fs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rz_fu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_vcvt_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_vcvt_uh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_hs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rz_hs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rz_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_vcvt_rm_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_vcvt_rm_us, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c index b9b3d1c1fb..f9ca889bec 100644 --- a/target/arm/tcg/translate-neon.c +++ b/target/arm/tcg/translate-neon.c @@ -1409,13 +1409,13 @@ static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, DO_FP_2SH(VCVT_SF, gen_helper_gvec_vcvt_sf) DO_FP_2SH(VCVT_UF, gen_helper_gvec_vcvt_uf) -DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_fs) -DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_fu) +DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_rz_fs) +DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_rz_fu) DO_FP_2SH(VCVT_SH, gen_helper_gvec_vcvt_sh) DO_FP_2SH(VCVT_UH, gen_helper_gvec_vcvt_uh) -DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_hs) -DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_hu) +DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_rz_hs) +DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_rz_hu) static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, GVecGen2iFn *fn) diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index 60381258cf..282dba4bfd 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -2507,12 +2507,12 @@ DO_3OP_PAIR(gvec_uminp_s, MIN, uint32_t, H4) DO_VCVT_FIXED(gvec_vcvt_sf, helper_vfp_sltos, uint32_t) DO_VCVT_FIXED(gvec_vcvt_uf, helper_vfp_ultos, uint32_t) -DO_VCVT_FIXED(gvec_vcvt_fs, helper_vfp_tosls_round_to_zero, uint32_t) -DO_VCVT_FIXED(gvec_vcvt_fu, helper_vfp_touls_round_to_zero, uint32_t) +DO_VCVT_FIXED(gvec_vcvt_rz_fs, helper_vfp_tosls_round_to_zero, uint32_t) +DO_VCVT_FIXED(gvec_vcvt_rz_fu, helper_vfp_touls_round_to_zero, uint32_t) DO_VCVT_FIXED(gvec_vcvt_sh, helper_vfp_shtoh, uint16_t) DO_VCVT_FIXED(gvec_vcvt_uh, helper_vfp_uhtoh, uint16_t) -DO_VCVT_FIXED(gvec_vcvt_hs, helper_vfp_toshh_round_to_zero, uint16_t) -DO_VCVT_FIXED(gvec_vcvt_hu, helper_vfp_touhh_round_to_zero, uint16_t) +DO_VCVT_FIXED(gvec_vcvt_rz_hs, helper_vfp_toshh_round_to_zero, uint16_t) +DO_VCVT_FIXED(gvec_vcvt_rz_hu, helper_vfp_touhh_round_to_zero, uint16_t) #undef DO_VCVT_FIXED -- 2.43.0
[PATCH v2 14/31] tests/functional: switch over to using self.socket_dir(...)
This removes direct creation of temporary dirs Signed-off-by: Daniel P. Berrangé --- tests/functional/test_arm_aspeed.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/functional/test_arm_aspeed.py b/tests/functional/test_arm_aspeed.py index 9561129c51..5bd31e43ee 100755 --- a/tests/functional/test_arm_aspeed.py +++ b/tests/functional/test_arm_aspeed.py @@ -9,7 +9,6 @@ import os import time import subprocess -import tempfile from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern @@ -226,7 +225,7 @@ def test_arm_ast2600_evb_buildroot_tpm(self): tpmstate_dir = self.scratch_file('swtpmstate') os.mkdir(tpmstate_dir) -socket_dir = tempfile.TemporaryDirectory(prefix="qemu_") +socket_dir = self.socket_dir() socket = os.path.join(socket_dir.name, 'swtpm-socket') # We must put the TPM state dir in /tmp/, not the build dir, -- 2.46.0
[PATCH v3 52/69] target/arm: Convert SHLL to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 75 +- target/arm/tcg/a64.decode | 2 + 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 1c454a37f4..c5d456de3b 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -9113,6 +9113,43 @@ static ArithOneOp * const f_vector_bfcvtn[] = { }; TRANS_FEAT(BFCVTN_v, aa64_bf16, do_2misc_narrow_vector, a, f_vector_bfcvtn) +static bool trans_SHLL_v(DisasContext *s, arg_qrr_e *a) +{ +static NeonGenWidenFn * const widenfns[3] = { +gen_helper_neon_widen_u8, +gen_helper_neon_widen_u16, +tcg_gen_extu_i32_i64, +}; +NeonGenWidenFn *widenfn; +TCGv_i64 tcg_res[2]; +TCGv_i32 tcg_op; +int part, pass; + +if (a->esz == MO_64) { +return false; +} +if (!fp_access_check(s)) { +return true; +} + +tcg_op = tcg_temp_new_i32(); +widenfn = widenfns[a->esz]; +part = a->q ? 2 : 0; + +for (pass = 0; pass < 2; pass++) { +read_vec_element_i32(s, tcg_op, a->rn, part + pass, MO_32); +tcg_res[pass] = tcg_temp_new_i64(); +widenfn(tcg_res[pass], tcg_op); +tcg_gen_shli_i64(tcg_res[pass], tcg_res[pass], 8 << a->esz); +} + +for (pass = 0; pass < 2; pass++) { +write_vec_element(s, tcg_res[pass], a->rd, pass, MO_64); +} +return true; +} + + /* Common vector code for handling integer to FP conversion */ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, int elements, int is_signed, @@ -9901,33 +9938,6 @@ static void handle_2misc_widening(DisasContext *s, int opcode, bool is_q, } } -static void handle_shll(DisasContext *s, bool is_q, int size, int rn, int rd) -{ -/* Implement SHLL and SHLL2 */ -int pass; -int part = is_q ? 2 : 0; -TCGv_i64 tcg_res[2]; - -for (pass = 0; pass < 2; pass++) { -static NeonGenWidenFn * const widenfns[3] = { -gen_helper_neon_widen_u8, -gen_helper_neon_widen_u16, -tcg_gen_extu_i32_i64, -}; -NeonGenWidenFn *widenfn = widenfns[size]; -TCGv_i32 tcg_op = tcg_temp_new_i32(); - -read_vec_element_i32(s, tcg_op, rn, part + pass, MO_32); -tcg_res[pass] = tcg_temp_new_i64(); -widenfn(tcg_res[pass], tcg_op); -tcg_gen_shli_i64(tcg_res[pass], tcg_res[pass], 8 << size); -} - -for (pass = 0; pass < 2; pass++) { -write_vec_element(s, tcg_res[pass], rd, pass, MO_64); -} -} - /* AdvSIMD two reg misc * 31 30 29 28 24 23 22 21 17 1612 11 10 95 40 * +---+---+---+---+--+---++-+--+--+ @@ -9948,16 +9958,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) TCGv_ptr tcg_fpstatus; switch (opcode) { -case 0x13: /* SHLL, SHLL2 */ -if (u == 0 || size == 3) { -unallocated_encoding(s); -return; -} -if (!fp_access_check(s)) { -return; -} -handle_shll(s, is_q, size, rn, rd); -return; case 0xc ... 0xf: case 0x16 ... 0x1f: { @@ -10118,6 +10118,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) case 0xa: /* CMLT */ case 0xb: /* ABS, NEG */ case 0x12: /* XTN, XTN2, SQXTUN, SQXTUN2 */ +case 0x13: /* SHLL, SHLL2 */ case 0x14: /* SQXTN, SQXTN2, UQXTN, UQXTN2 */ unallocated_encoding(s); return; diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index d8902dfb22..ec0d46a563 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -1685,3 +1685,5 @@ UQXTN_v 0.10 1110 ..1 1 01001 0 . . @qrr_e FCVTN_v 0.00 1110 0.1 1 01101 0 . . @qrr_hs FCVTXN_v0.10 1110 011 1 01101 0 . . @qrr_s BFCVTN_v0.00 1110 101 1 01101 0 . . @qrr_h + +SHLL_v 0.10 1110 ..1 1 00111 0 . . @qrr_e -- 2.43.0
[PATCH v3 14/69] target/arm: Convert disas_data_proc_3src to decodetree
This includes MADD, MSUB, SMADDL, SMSUBL, UMADDL, UMSUBL, SMULH, UMULH. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 119 - target/arm/tcg/a64.decode | 16 + 2 files changed, 59 insertions(+), 76 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index d570bbb696..99ff787c61 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -7955,98 +7955,68 @@ TRANS(SUB_r, do_addsub_reg, a, true, false) TRANS(ADDS_r, do_addsub_reg, a, false, true) TRANS(SUBS_r, do_addsub_reg, a, true, true) -/* Data-processing (3 source) - * - *31 30 29 28 24 23 21 20 16 15 14 10 95 40 - * +--+--+---+--+--++--+--+--+ - * |sf| op54 | 1 1 0 1 1 | op31 | Rm | o0 | Ra | Rn | Rd | - * +--+--+---+--+--++--+--+--+ - */ -static void disas_data_proc_3src(DisasContext *s, uint32_t insn) +static bool do_mulh(DisasContext *s, arg_rrr *a, +void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) { -int rd = extract32(insn, 0, 5); -int rn = extract32(insn, 5, 5); -int ra = extract32(insn, 10, 5); -int rm = extract32(insn, 16, 5); -int op_id = (extract32(insn, 29, 3) << 4) | -(extract32(insn, 21, 3) << 1) | -extract32(insn, 15, 1); -bool sf = extract32(insn, 31, 1); -bool is_sub = extract32(op_id, 0, 1); -bool is_high = extract32(op_id, 2, 1); -bool is_signed = false; -TCGv_i64 tcg_op1; -TCGv_i64 tcg_op2; -TCGv_i64 tcg_tmp; +TCGv_i64 discard = tcg_temp_new_i64(); +TCGv_i64 tcg_rd = cpu_reg(s, a->rd); +TCGv_i64 tcg_rn = cpu_reg(s, a->rn); +TCGv_i64 tcg_rm = cpu_reg(s, a->rm); -/* Note that op_id is sf:op54:op31:o0 so it includes the 32/64 size flag */ -switch (op_id) { -case 0x42: /* SMADDL */ -case 0x43: /* SMSUBL */ -case 0x44: /* SMULH */ -is_signed = true; -break; -case 0x0: /* MADD (32bit) */ -case 0x1: /* MSUB (32bit) */ -case 0x40: /* MADD (64bit) */ -case 0x41: /* MSUB (64bit) */ -case 0x4a: /* UMADDL */ -case 0x4b: /* UMSUBL */ -case 0x4c: /* UMULH */ -break; -default: -unallocated_encoding(s); -return; -} +fn(discard, tcg_rd, tcg_rn, tcg_rm); +return true; +} -if (is_high) { -TCGv_i64 low_bits = tcg_temp_new_i64(); /* low bits discarded */ -TCGv_i64 tcg_rd = cpu_reg(s, rd); -TCGv_i64 tcg_rn = cpu_reg(s, rn); -TCGv_i64 tcg_rm = cpu_reg(s, rm); +TRANS(SMULH, do_mulh, a, tcg_gen_muls2_i64) +TRANS(UMULH, do_mulh, a, tcg_gen_mulu2_i64) -if (is_signed) { -tcg_gen_muls2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm); -} else { -tcg_gen_mulu2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm); -} -return; -} +static bool do_muladd(DisasContext *s, arg_ *a, + bool sf, bool is_sub, MemOp mop) +{ +TCGv_i64 tcg_rd = cpu_reg(s, a->rd); +TCGv_i64 tcg_op1, tcg_op2; -tcg_op1 = tcg_temp_new_i64(); -tcg_op2 = tcg_temp_new_i64(); -tcg_tmp = tcg_temp_new_i64(); - -if (op_id < 0x42) { -tcg_gen_mov_i64(tcg_op1, cpu_reg(s, rn)); -tcg_gen_mov_i64(tcg_op2, cpu_reg(s, rm)); +if (mop == MO_64) { +tcg_op1 = cpu_reg(s, a->rn); +tcg_op2 = cpu_reg(s, a->rm); } else { -if (is_signed) { -tcg_gen_ext32s_i64(tcg_op1, cpu_reg(s, rn)); -tcg_gen_ext32s_i64(tcg_op2, cpu_reg(s, rm)); -} else { -tcg_gen_ext32u_i64(tcg_op1, cpu_reg(s, rn)); -tcg_gen_ext32u_i64(tcg_op2, cpu_reg(s, rm)); -} +tcg_op1 = tcg_temp_new_i64(); +tcg_op2 = tcg_temp_new_i64(); +tcg_gen_ext_i64(tcg_op1, cpu_reg(s, a->rn), mop); +tcg_gen_ext_i64(tcg_op2, cpu_reg(s, a->rm), mop); } -if (ra == 31 && !is_sub) { +if (a->ra == 31 && !is_sub) { /* Special-case MADD with rA == XZR; it is the standard MUL alias */ -tcg_gen_mul_i64(cpu_reg(s, rd), tcg_op1, tcg_op2); +tcg_gen_mul_i64(tcg_rd, tcg_op1, tcg_op2); } else { +TCGv_i64 tcg_tmp = tcg_temp_new_i64(); +TCGv_i64 tcg_ra = cpu_reg(s, a->ra); + tcg_gen_mul_i64(tcg_tmp, tcg_op1, tcg_op2); if (is_sub) { -tcg_gen_sub_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp); +tcg_gen_sub_i64(tcg_rd, tcg_ra, tcg_tmp); } else { -tcg_gen_add_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp); +tcg_gen_add_i64(tcg_rd, tcg_ra, tcg_tmp); } } if (!sf) { -tcg_gen_ext32u_i64(cpu_reg(s, rd), cpu_reg(s, rd)); +tcg_gen_ext32u_i64(tcg_rd, tcg_rd); } +return true; } +TRANS(MADD_w, do_muladd, a, false, false, MO_64) +TRANS(MSUB_w, do_muladd, a, false, true, MO_64) +TRANS(MADD_x, do_
[PULL 32/49] ui: Replace type_register() with type_register_static()
From: Zhao Liu Replace type_register() with type_register_static() because type_register() will be deprecated. Signed-off-by: Zhao Liu Signed-off-by: Paolo Bonzini Link: https://lore.kernel.org/r/20241029085934.2799066-15-zhao1@intel.com --- ui/console-vc.c | 2 +- ui/dbus.c | 2 +- ui/gtk.c| 2 +- ui/spice-app.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/console-vc.c b/ui/console-vc.c index 53fcee88f4a..fe20579832a 100644 --- a/ui/console-vc.c +++ b/ui/console-vc.c @@ -1073,6 +1073,6 @@ void qemu_console_early_init(void) { /* set the default vc driver */ if (!object_class_by_name(TYPE_CHARDEV_VC)) { -type_register(&char_vc_type_info); +type_register_static(&char_vc_type_info); } } diff --git a/ui/dbus.c b/ui/dbus.c index 7ecd39e784a..d60b59cc546 100644 --- a/ui/dbus.c +++ b/ui/dbus.c @@ -476,7 +476,7 @@ early_dbus_init(DisplayOptions *opts) #endif } -type_register(&dbus_vc_type_info); +type_register_static(&dbus_vc_type_info); } static void diff --git a/ui/gtk.c b/ui/gtk.c index bf9d3dd679a..f9a53ea78ed 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -2540,7 +2540,7 @@ static void early_gtk_display_init(DisplayOptions *opts) keycode_map = gd_get_keymap(&keycode_maplen); #if defined(CONFIG_VTE) -type_register(&char_gd_vc_type_info); +type_register_static(&char_gd_vc_type_info); #endif } diff --git a/ui/spice-app.c b/ui/spice-app.c index a10b4a58fe7..2a93ae59184 100644 --- a/ui/spice-app.c +++ b/ui/spice-app.c @@ -173,7 +173,7 @@ static void spice_app_display_early_init(DisplayOptions *opts) exit(1); } -type_register(&char_vc_type_info); +type_register_static(&char_vc_type_info); sock_path = g_strjoin("", app_dir, "/", "spice.sock", NULL); qopts = qemu_opts_create(list, NULL, 0, &error_abort); -- 2.47.1
[PATCH v3 25/69] target/arm: Pass fpstatus to vfp_sqrt*
Pass fpstatus not env, like most other fp helpers. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/helper.h| 6 +++--- target/arm/tcg/translate-a64.c | 15 +++ target/arm/tcg/translate-vfp.c | 6 +++--- target/arm/vfp_helper.c| 12 ++-- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 58919b670e..0a697e752b 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -133,9 +133,9 @@ DEF_HELPER_3(vfp_maxnumd, f64, f64, f64, ptr) DEF_HELPER_3(vfp_minnumh, f16, f16, f16, ptr) DEF_HELPER_3(vfp_minnums, f32, f32, f32, ptr) DEF_HELPER_3(vfp_minnumd, f64, f64, f64, ptr) -DEF_HELPER_2(vfp_sqrth, f16, f16, env) -DEF_HELPER_2(vfp_sqrts, f32, f32, env) -DEF_HELPER_2(vfp_sqrtd, f64, f64, env) +DEF_HELPER_2(vfp_sqrth, f16, f16, ptr) +DEF_HELPER_2(vfp_sqrts, f32, f32, ptr) +DEF_HELPER_2(vfp_sqrtd, f64, f64, ptr) DEF_HELPER_3(vfp_cmph, void, f16, f16, env) DEF_HELPER_3(vfp_cmps, void, f32, f32, env) DEF_HELPER_3(vfp_cmpd, void, f64, f64, env) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index ca2b95510e..cfc73b8506 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8401,8 +8401,8 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn) switch (opcode) { case 0x3: /* FSQRT */ -gen_helper_vfp_sqrts(tcg_res, tcg_op, tcg_env); -goto done; +gen_fpst = gen_helper_vfp_sqrts; +break; case 0x6: /* BFCVT */ gen_fpst = gen_helper_bfcvt; break; @@ -8450,7 +8450,6 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn) gen_fpst(tcg_res, tcg_op, fpst); } - done: write_fp_sreg(s, rd, tcg_res); } @@ -8467,8 +8466,8 @@ static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn) switch (opcode) { case 0x3: /* FSQRT */ -gen_helper_vfp_sqrtd(tcg_res, tcg_op, tcg_env); -goto done; +gen_fpst = gen_helper_vfp_sqrtd; +break; case 0x8: /* FRINTN */ case 0x9: /* FRINTP */ case 0xa: /* FRINTM */ @@ -8513,7 +8512,6 @@ static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn) gen_fpst(tcg_res, tcg_op, fpst); } - done: write_fp_dreg(s, rd, tcg_res); } @@ -9459,7 +9457,7 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, gen_vfp_negd(tcg_rd, tcg_rn); break; case 0x7f: /* FSQRT */ -gen_helper_vfp_sqrtd(tcg_rd, tcg_rn, tcg_env); +gen_helper_vfp_sqrtd(tcg_rd, tcg_rn, tcg_fpstatus); break; case 0x1a: /* FCVTNS */ case 0x1b: /* FCVTMS */ @@ -10402,6 +10400,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) handle_2misc_fcmp_zero(s, opcode, false, u, is_q, size, rn, rd); return; case 0x7f: /* FSQRT */ +need_fpstatus = true; if (size == 3 && !is_q) { unallocated_encoding(s); return; @@ -10631,7 +10630,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) gen_vfp_negs(tcg_res, tcg_op); break; case 0x7f: /* FSQRT */ -gen_helper_vfp_sqrts(tcg_res, tcg_op, tcg_env); +gen_helper_vfp_sqrts(tcg_res, tcg_op, tcg_fpstatus); break; case 0x1a: /* FCVTNS */ case 0x1b: /* FCVTMS */ diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c index b6fa28a7bf..c160a86e70 100644 --- a/target/arm/tcg/translate-vfp.c +++ b/target/arm/tcg/translate-vfp.c @@ -2424,17 +2424,17 @@ DO_VFP_2OP(VNEG, dp, gen_vfp_negd, aa32_fpdp_v2) static void gen_VSQRT_hp(TCGv_i32 vd, TCGv_i32 vm) { -gen_helper_vfp_sqrth(vd, vm, tcg_env); +gen_helper_vfp_sqrth(vd, vm, fpstatus_ptr(FPST_FPCR_F16)); } static void gen_VSQRT_sp(TCGv_i32 vd, TCGv_i32 vm) { -gen_helper_vfp_sqrts(vd, vm, tcg_env); +gen_helper_vfp_sqrts(vd, vm, fpstatus_ptr(FPST_FPCR)); } static void gen_VSQRT_dp(TCGv_i64 vd, TCGv_i64 vm) { -gen_helper_vfp_sqrtd(vd, vm, tcg_env); +gen_helper_vfp_sqrtd(vd, vm, fpstatus_ptr(FPST_FPCR)); } DO_VFP_2OP(VSQRT, hp, gen_VSQRT_hp, aa32_fp16_arith) diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 62638d2b1f..f24992c798 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -314,19 +314,19 @@ VFP_BINOP(minnum) VFP_BINOP(maxnum) #undef VFP_BINOP -dh_ctype_f16 VFP_HELPER(sqrt, h)(dh_ctype_f16 a, CPUARMState *env) +dh_ctype_f16 VFP_HELPER(sqrt, h)(dh_ctype_f16 a, void *fpstp) { -return float16_sqrt(a, &env->vfp.fp_status_f16); +return float16_sqrt(a, fpstp); } -float32 VFP_HELPER(sqrt, s)(float32 a, CPUARMState *env) +float32 VFP_HELPER(sqrt, s)(float32 a, void *fp
[PATCH v3 41/69] target/arm: Convert CMGT, CMGE, GMLT, GMLE, CMEQ (zero) to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 94 +++--- target/arm/tcg/a64.decode | 10 2 files changed, 40 insertions(+), 64 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index aff1984a22..547c6dc5cc 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8902,6 +8902,22 @@ static bool do_scalar1_d(DisasContext *s, arg_rr *a, ArithOneOp *f) TRANS(ABS_s, do_scalar1_d, a, tcg_gen_abs_i64) TRANS(NEG_s, do_scalar1_d, a, tcg_gen_neg_i64) +static bool do_cmop0_d(DisasContext *s, arg_rr *a, TCGCond cond) +{ +if (fp_access_check(s)) { +TCGv_i64 t = read_fp_dreg(s, a->rn); +tcg_gen_negsetcond_i64(cond, t, t, tcg_constant_i64(0)); +write_fp_dreg(s, a->rd, t); +} +return true; +} + +TRANS(CMGT0_s, do_cmop0_d, a, TCG_COND_GT) +TRANS(CMGE0_s, do_cmop0_d, a, TCG_COND_GE) +TRANS(CMLE0_s, do_cmop0_d, a, TCG_COND_LE) +TRANS(CMLT0_s, do_cmop0_d, a, TCG_COND_LT) +TRANS(CMEQ0_s, do_cmop0_d, a, TCG_COND_EQ) + static bool do_gvec_fn2(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) { if (!a->q && a->esz == MO_64) { @@ -8918,6 +8934,11 @@ TRANS(NEG_v, do_gvec_fn2, a, tcg_gen_gvec_neg) TRANS(NOT_v, do_gvec_fn2, a, tcg_gen_gvec_not) TRANS(CNT_v, do_gvec_fn2, a, gen_gvec_cnt) TRANS(RBIT_v, do_gvec_fn2, a, gen_gvec_rbit) +TRANS(CMGT0_v, do_gvec_fn2, a, gen_gvec_cgt0) +TRANS(CMGE0_v, do_gvec_fn2, a, gen_gvec_cge0) +TRANS(CMLT0_v, do_gvec_fn2, a, gen_gvec_clt0) +TRANS(CMLE0_v, do_gvec_fn2, a, gen_gvec_cle0) +TRANS(CMEQ0_v, do_gvec_fn2, a, gen_gvec_ceq0) static bool do_gvec_fn2_bhs(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) { @@ -9229,21 +9250,7 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, * The caller only need provide tcg_rmode and tcg_fpstatus if the op * requires them. */ -TCGCond cond; - switch (opcode) { -case 0xa: /* CMLT */ -cond = TCG_COND_LT; -do_cmop: -/* 64 bit integer comparison against zero, result is test ? -1 : 0. */ -tcg_gen_negsetcond_i64(cond, tcg_rd, tcg_rn, tcg_constant_i64(0)); -break; -case 0x8: /* CMGT, CMGE */ -cond = u ? TCG_COND_GE : TCG_COND_GT; -goto do_cmop; -case 0x9: /* CMEQ, CMLE */ -cond = u ? TCG_COND_LE : TCG_COND_EQ; -goto do_cmop; case 0x2f: /* FABS */ gen_vfp_absd(tcg_rd, tcg_rn); break; @@ -9290,6 +9297,9 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, case 0x4: /* CLS, CLZ */ case 0x5: /* NOT */ case 0x7: /* SQABS, SQNEG */ +case 0x8: /* CMGT, CMGE */ +case 0x9: /* CMEQ, CMLE */ +case 0xa: /* CMLT */ case 0xb: /* ABS, NEG */ g_assert_not_reached(); } @@ -9633,19 +9643,6 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) TCGv_ptr tcg_fpstatus; switch (opcode) { -case 0xa: /* CMLT */ -if (u) { -unallocated_encoding(s); -return; -} -/* fall through */ -case 0x8: /* CMGT, CMGE */ -case 0x9: /* CMEQ, CMLE */ -if (size != 3) { -unallocated_encoding(s); -return; -} -break; case 0x12: /* SQXTUN */ if (!u) { unallocated_encoding(s); @@ -9731,6 +9728,9 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) default: case 0x3: /* USQADD / SUQADD */ case 0x7: /* SQABS / SQNEG */ +case 0x8: /* CMGT, CMGE */ +case 0x9: /* CMEQ, CMLE */ +case 0xa: /* CMLT */ case 0xb: /* ABS, NEG */ unallocated_encoding(s); return; @@ -10103,19 +10103,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) } handle_shll(s, is_q, size, rn, rd); return; -case 0xa: /* CMLT */ -if (u == 1) { -unallocated_encoding(s); -return; -} -/* fall through */ -case 0x8: /* CMGT, CMGE */ -case 0x9: /* CMEQ, CMLE */ -if (size == 3 && !is_q) { -unallocated_encoding(s); -return; -} -break; case 0xc ... 0xf: case 0x16 ... 0x1f: { @@ -10289,6 +10276,9 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) case 0x4: /* CLS, CLZ */ case 0x5: /* CNT, NOT, RBIT */ case 0x7: /* SQABS, SQNEG */ +case 0x8: /* CMGT, CMGE */ +case 0x9: /* CMEQ, CMLE */ +case 0xa: /* CMLT */ case 0xb: /* ABS, NEG */ unallocated_encoding(s); return; @@ -10309,30 +10299,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) tcg_rmode = NULL; } -switch (opcode) { -case 0x8: /* CMGT, CMGE */ -if (u) { -gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cge0, size); -} else { -gen_gvec_fn2(s, is_q,
[PATCH v3 12/69] target/arm: Convert disas_add_sub_ext_reg to decodetree
This includes ADD, SUB, ADDS, SUBS (extended register). Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 65 +++--- target/arm/tcg/a64.decode | 9 + 2 files changed, 29 insertions(+), 45 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index ecc8899dd8..8f777875fe 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -7864,57 +7864,27 @@ TRANS(AND_r, do_logic_reg, a, tcg_gen_and_i64, tcg_gen_andc_i64, false) TRANS(ANDS_r, do_logic_reg, a, tcg_gen_and_i64, tcg_gen_andc_i64, true) TRANS(EOR_r, do_logic_reg, a, tcg_gen_xor_i64, tcg_gen_eqv_i64, false) -/* - * Add/subtract (extended register) - * - * 31|30|29|28 24|23 22|21|20 16|15 13|12 10|9 5|4 0| - * +--+--+--+---+-+--+---+--+--+++ - * |sf|op| S| 0 1 0 1 1 | opt | 1| Rm |option| imm3 | Rn | Rd | - * +--+--+--+---+-+--+---+--+--+++ - * - * sf: 0 -> 32bit, 1 -> 64bit - * op: 0 -> add , 1 -> sub - * S: 1 -> set flags - * opt: 00 - * option: extension type (see DecodeRegExtend) - * imm3: optional shift to Rm - * - * Rd = Rn + LSL(extend(Rm), amount) - */ -static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn) +static bool do_addsub_ext(DisasContext *s, arg_addsub_ext *a, + bool sub_op, bool setflags) { -int rd = extract32(insn, 0, 5); -int rn = extract32(insn, 5, 5); -int imm3 = extract32(insn, 10, 3); -int option = extract32(insn, 13, 3); -int rm = extract32(insn, 16, 5); -int opt = extract32(insn, 22, 2); -bool setflags = extract32(insn, 29, 1); -bool sub_op = extract32(insn, 30, 1); -bool sf = extract32(insn, 31, 1); +TCGv_i64 tcg_rm, tcg_rn, tcg_rd, tcg_result; -TCGv_i64 tcg_rm, tcg_rn; /* temps */ -TCGv_i64 tcg_rd; -TCGv_i64 tcg_result; - -if (imm3 > 4 || opt != 0) { -unallocated_encoding(s); -return; +if (a->sa > 4) { +return false; } /* non-flag setting ops may use SP */ if (!setflags) { -tcg_rd = cpu_reg_sp(s, rd); +tcg_rd = cpu_reg_sp(s, a->rd); } else { -tcg_rd = cpu_reg(s, rd); +tcg_rd = cpu_reg(s, a->rd); } -tcg_rn = read_cpu_reg_sp(s, rn, sf); +tcg_rn = read_cpu_reg_sp(s, a->rn, a->sf); -tcg_rm = read_cpu_reg(s, rm, sf); -ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3); +tcg_rm = read_cpu_reg(s, a->rm, a->sf); +ext_and_shift_reg(tcg_rm, tcg_rm, a->st, a->sa); tcg_result = tcg_temp_new_i64(); - if (!setflags) { if (sub_op) { tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm); @@ -7923,19 +7893,25 @@ static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn) } } else { if (sub_op) { -gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm); +gen_sub_CC(a->sf, tcg_result, tcg_rn, tcg_rm); } else { -gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm); +gen_add_CC(a->sf, tcg_result, tcg_rn, tcg_rm); } } -if (sf) { +if (a->sf) { tcg_gen_mov_i64(tcg_rd, tcg_result); } else { tcg_gen_ext32u_i64(tcg_rd, tcg_result); } +return true; } +TRANS(ADD_ext, do_addsub_ext, a, false, false) +TRANS(SUB_ext, do_addsub_ext, a, true, false) +TRANS(ADDS_ext, do_addsub_ext, a, false, true) +TRANS(SUBS_ext, do_addsub_ext, a, true, true) + /* * Add/subtract (shifted register) * @@ -8374,8 +8350,7 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) if (!op1) { if (op2 & 8) { if (op2 & 1) { -/* Add/sub (extended register) */ -disas_add_sub_ext_reg(s, insn); +goto do_unallocated; } else { /* Add/sub (shifted register) */ disas_add_sub_reg(s, insn); diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index 8e2949d236..0539694506 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -727,6 +727,15 @@ ANDS_r . 11 01010 .. . . .. . . @logic_shift # Add/subtract (shifted reg) # Add/subtract (extended reg) + +&addsub_ext rd rn rm sf sa st +@addsub_ext sf:1 .. rm:5 st:3 sa:3 rn:5 rd:5 &addsub_ext + +ADD_ext . 00 01011001 . ... ... . . @addsub_ext +SUB_ext . 10 01011001 . ... ... . . @addsub_ext +ADDS_ext. 01 01011001 . ... ... . . @addsub_ext +SUBS_ext. 11 01011001 . ... ... . . @addsub_ext + # Add/subtract (carry) # Rotate right into flags # Evaluate into flags -- 2.43.0
Re: [PATCH v2 01/31] tests/functional: remove many unused imports
On 11/12/2024 18.26, Daniel P. Berrangé wrote: Identified using 'pylint --disable=all --enable=W0611' Reviewed-by: Thomas Huth Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/asset.py | 1 - tests/functional/qemu_test/tesseract.py | 1 - tests/functional/qemu_test/tuxruntest.py | 3 +-- tests/functional/test_aarch64_aspeed.py | 1 - tests/functional/test_aarch64_sbsaref_alpine.py | 1 - tests/functional/test_aarch64_sbsaref_freebsd.py | 1 - tests/functional/test_acpi_bits.py | 2 -- tests/functional/test_arm_aspeed.py | 1 - tests/functional/test_arm_bpim2u.py | 2 +- tests/functional/test_arm_collie.py | 2 +- tests/functional/test_arm_cubieboard.py | 1 - tests/functional/test_arm_orangepi.py| 2 +- tests/functional/test_arm_smdkc210.py| 3 +-- tests/functional/test_arm_sx1.py | 2 +- tests/functional/test_microblaze_s3adsp1800.py | 1 - tests/functional/test_ppc_amiga.py | 2 +- tests/functional/test_virtio_gpu.py | 1 - tests/lcitool/libvirt-ci | 2 +- 18 files changed, 8 insertions(+), 21 deletions(-) ... diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci index 9ad3f70bde..0f11966131 16 --- a/tests/lcitool/libvirt-ci +++ b/tests/lcitool/libvirt-ci @@ -1 +1 @@ -Subproject commit 9ad3f70bde9865d5ad18f36d256d472e72b5cbf3 +Subproject commit 0f119661317333038e91b6fb9d0381a6934dcd0c That one seems unintentional? Thomas
Re: [PATCH v2 04/31] tests/functional: simplify 'which' implementation
On 11/12/2024 18.26, Daniel P. Berrangé wrote: The 'access' check implies the file exists. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/cmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index 4106f1ee7c..600e0509db 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -25,7 +25,7 @@ def which(tool): paths=os.getenv('PATH') for p in paths.split(os.path.pathsep): p = os.path.join(p, tool) -if os.path.exists(p) and os.access(p, os.X_OK): +if os.access(p, os.X_OK): return p return None Reviewed-by: Thomas Huth
[PATCH 1/3] scripts/qemu-gdb: Always do full stack dump for python errors
It's easier for either debugging plugin errors, or issue reports. Signed-off-by: Peter Xu --- scripts/qemu-gdb.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/qemu-gdb.py b/scripts/qemu-gdb.py index 4d2a9f6c43..cfae94a2e9 100644 --- a/scripts/qemu-gdb.py +++ b/scripts/qemu-gdb.py @@ -45,3 +45,5 @@ def __init__(self): # Default to silently passing through SIGUSR1, because QEMU sends it # to itself a lot. gdb.execute('handle SIGUSR1 pass noprint nostop') +# Always print full stack for python errors, easier to debug and report issues +gdb.execute('set python print-stack full') -- 2.47.0
[PATCH 3/3] scripts/qemu-gdb: Support coroutine dumps in coredumps
Dumping coroutines don't yet work with coredumps. Let's make it work. We still kept most of the old code because they can be either more flexible, or prettier. Only add the fallbacks when they stop working. Currently the raw unwind is pretty ugly, but it works, like this: (gdb) qemu bt Coroutine at 0x7fc474728748: Signed-off-by: Peter Xu --- scripts/qemugdb/coroutine.py | 50 +++- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py index 20f76ed37b..b29ee16205 100644 --- a/scripts/qemugdb/coroutine.py +++ b/scripts/qemugdb/coroutine.py @@ -46,9 +46,30 @@ def get_jmpbuf_regs(jmpbuf): 'r15': jmpbuf[JB_R15], 'rip': glibc_ptr_demangle(jmpbuf[JB_PC], pointer_guard) } -def bt_jmpbuf(jmpbuf): -'''Backtrace a jmpbuf''' -regs = get_jmpbuf_regs(jmpbuf) +def symbol_lookup(addr): +# Example: "__clone3 + 44 in section .text of /lib64/libc.so.6" +result = gdb.execute(f"info symbol {hex(addr)}", to_string=True).strip() +return result.split(" in ")[0] + +def dump_backtrace(regs): +''' +Backtrace dump with raw registers, mimic GDB command 'bt'. +''' +# Here only rbp and rip that matter.. +rbp = regs['rbp'] +rip = regs['rip'] +i = 0 + +while rbp: +print(f"#{i}\t{symbol_lookup(rip)}") +rip = gdb.parse_and_eval(f"*(uint64_t *)(uint64_t)({hex(rbp)} + 8)") +rbp = gdb.parse_and_eval(f"*(uint64_t *)(uint64_t)({hex(rbp)})") +i += 1 + +def dump_backtrace_live(regs): +''' +Backtrace dump with gdb's 'bt' command, only usable in a live session. +''' old = dict() # remember current stack frame and select the topmost @@ -69,6 +90,17 @@ def bt_jmpbuf(jmpbuf): selected_frame.select() +def bt_jmpbuf(jmpbuf): +'''Backtrace a jmpbuf''' +regs = get_jmpbuf_regs(jmpbuf) +try: +# This reuses gdb's "bt" command, which can be slightly prettier +# but only works with live sessions. +dump_backtrace_live(regs) +except: +# If above doesn't work, fallback to poor man's unwind +dump_backtrace(regs) + def co_cast(co): return co.cast(gdb.lookup_type('CoroutineUContext').pointer()) @@ -101,10 +133,14 @@ def invoke(self, arg, from_tty): gdb.execute("bt") -if gdb.parse_and_eval("qemu_in_coroutine()") == False: -return - -co_ptr = gdb.parse_and_eval("qemu_coroutine_self()") +try: +# This only works with a live session +co_ptr = gdb.parse_and_eval("qemu_coroutine_self()") +if co_ptr == False: +return +except: +# Fallback to use hard-coded ucontext vars if it's coredump +co_ptr = gdb.parse_and_eval("co_tls_current") while True: co = co_cast(co_ptr) -- 2.47.0
[PATCH 0/3] scripts/qemu-gdb: Make coroutine dumps to work with coredumps
Coroutines are used in many cases in block layers. It's also used in live migration when on destination side, and it'll be handy to diagnose crashes within a coroutine when we want to also know what other coroutines are doing. This series adds initial support for that, not pretty but it should start working. Since we can't use the trick to modify registers on the fly in non-live gdb sessions, we do manual unwinds. Thanks, Peter Xu (3): scripts/qemu-gdb: Always do full stack dump for python errors scripts/qemu-gdb: Simplify fs_base fetching for coroutines scripts/qemu-gdb: Support coroutine dumps in coredumps scripts/qemu-gdb.py | 2 + scripts/qemugdb/coroutine.py | 73 ++-- 2 files changed, 47 insertions(+), 28 deletions(-) -- 2.47.0
[PATCH 2/3] scripts/qemu-gdb: Simplify fs_base fetching for coroutines
There're a bunch of code trying to fetch fs_base in different ways. IIUC the simplest way instead is "$fs_base". It also has the benefit that it'll work for both live gdb session or coredumps. Signed-off-by: Peter Xu --- scripts/qemugdb/coroutine.py | 23 ++- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py index 7db46d4b68..20f76ed37b 100644 --- a/scripts/qemugdb/coroutine.py +++ b/scripts/qemugdb/coroutine.py @@ -13,28 +13,9 @@ VOID_PTR = gdb.lookup_type('void').pointer() -def get_fs_base(): -'''Fetch %fs base value using arch_prctl(ARCH_GET_FS). This is - pthread_self().''' -# %rsp - 120 is scratch space according to the SystemV ABI -old = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)') -gdb.execute('call (int)arch_prctl(0x1003, $rsp - 120)', False, True) -fs_base = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)') -gdb.execute('set *(uint64_t*)($rsp - 120) = %s' % old, False, True) -return fs_base - def pthread_self(): -'''Fetch pthread_self() from the glibc start_thread function.''' -f = gdb.newest_frame() -while f.name() != 'start_thread': -f = f.older() -if f is None: -return get_fs_base() - -try: -return f.read_var("arg") -except ValueError: -return get_fs_base() +'''Fetch the base address of TLS.''' +return gdb.parse_and_eval("$fs_base") def get_glibc_pointer_guard(): '''Fetch glibc pointer guard value''' -- 2.47.0
Re: [PATCH 3/3] scripts/qemu-gdb: Support coroutine dumps in coredumps
On Wed, Dec 11, 2024 at 03:17:39PM -0500, Peter Xu wrote: > Dumping coroutines don't yet work with coredumps. Let's make it work. > > We still kept most of the old code because they can be either more > flexible, or prettier. Only add the fallbacks when they stop working. > > Currently the raw unwind is pretty ugly, but it works, like this: > > (gdb) qemu bt > Coroutine at 0x7fc474728748: It didn't get commited.. I forgot to indent. It looks like this: (gdb) qemu bt #0 process_incoming_migration_co (opaque=0x0) at ../migration/migration.c:788 #1 0x55cf3894d4d9 in coroutine_trampoline (i0=1565638480, i1=21967) at ../util/coroutine-ucontext.c:175 #2 0x7fc481f72f40 in ??? () at /lib64/libc.so.6 #3 0x7ffc0c74a520 in ??? () #4 0x in ??? () Coroutine at 0x7fc474728748: #0 qemu_coroutine_switch + 120 #1 qemu_aio_coroutine_enter + 357 #2 qemu_coroutine_enter + 35 #3 migration_incoming_process + 44 #4 migration_ioc_process_incoming + 491 #5 migration_channel_process_incoming + 146 #6 socket_accept_incoming_migration + 119 #7 qio_net_listener_channel_func + 132 #8 qio_channel_fd_source_dispatch + 79 #9 g_main_context_dispatch_unlocked.lto_priv + 316 #10 g_main_context_dispatch + 37 #11 glib_pollfds_poll + 91 #12 os_host_main_loop_wait + 129 #13 main_loop_wait + 204 #14 qemu_main_loop + 42 #15 qemu_default_main + 20 #16 main + 41 #17 __libc_start_call_main + 120 #18 __libc_start_main_impl + 139 > > Signed-off-by: Peter Xu > --- > scripts/qemugdb/coroutine.py | 50 +++- > 1 file changed, 43 insertions(+), 7 deletions(-) > > diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py > index 20f76ed37b..b29ee16205 100644 > --- a/scripts/qemugdb/coroutine.py > +++ b/scripts/qemugdb/coroutine.py > @@ -46,9 +46,30 @@ def get_jmpbuf_regs(jmpbuf): > 'r15': jmpbuf[JB_R15], > 'rip': glibc_ptr_demangle(jmpbuf[JB_PC], pointer_guard) } > > -def bt_jmpbuf(jmpbuf): > -'''Backtrace a jmpbuf''' > -regs = get_jmpbuf_regs(jmpbuf) > +def symbol_lookup(addr): > +# Example: "__clone3 + 44 in section .text of /lib64/libc.so.6" > +result = gdb.execute(f"info symbol {hex(addr)}", to_string=True).strip() > +return result.split(" in ")[0] > + > +def dump_backtrace(regs): > +''' > +Backtrace dump with raw registers, mimic GDB command 'bt'. > +''' > +# Here only rbp and rip that matter.. > +rbp = regs['rbp'] > +rip = regs['rip'] > +i = 0 > + > +while rbp: > +print(f"#{i}\t{symbol_lookup(rip)}") > +rip = gdb.parse_and_eval(f"*(uint64_t *)(uint64_t)({hex(rbp)} + 8)") > +rbp = gdb.parse_and_eval(f"*(uint64_t *)(uint64_t)({hex(rbp)})") > +i += 1 > + > +def dump_backtrace_live(regs): > +''' > +Backtrace dump with gdb's 'bt' command, only usable in a live session. > +''' > old = dict() > > # remember current stack frame and select the topmost > @@ -69,6 +90,17 @@ def bt_jmpbuf(jmpbuf): > > selected_frame.select() > > +def bt_jmpbuf(jmpbuf): > +'''Backtrace a jmpbuf''' > +regs = get_jmpbuf_regs(jmpbuf) > +try: > +# This reuses gdb's "bt" command, which can be slightly prettier > +# but only works with live sessions. > +dump_backtrace_live(regs) > +except: > +# If above doesn't work, fallback to poor man's unwind > +dump_backtrace(regs) > + > def co_cast(co): > return co.cast(gdb.lookup_type('CoroutineUContext').pointer()) > > @@ -101,10 +133,14 @@ def invoke(self, arg, from_tty): > > gdb.execute("bt") > > -if gdb.parse_and_eval("qemu_in_coroutine()") == False: > -return > - > -co_ptr = gdb.parse_and_eval("qemu_coroutine_self()") > +try: > +# This only works with a live session > +co_ptr = gdb.parse_and_eval("qemu_coroutine_self()") > +if co_ptr == False: > +return > +except: > +# Fallback to use hard-coded ucontext vars if it's coredump > +co_ptr = gdb.parse_and_eval("co_tls_current") > > while True: > co = co_cast(co_ptr) > -- > 2.47.0 > -- Peter Xu
Re: [PATCH 0/3] scripts/qemu-gdb: Make coroutine dumps to work with coredumps
Peter Xu writes: > Coroutines are used in many cases in block layers. It's also used in live > migration when on destination side, and it'll be handy to diagnose crashes > within a coroutine when we want to also know what other coroutines are > doing. Not sure if you've seen this message on the list: https://lore.kernel.org/r/f0ebccca-7a17-4da8-ac4a-71cf6d69a...@mtasv.net
Re: [PATCH 2/2] s390x/pci: indicate QEMU supports relaxed translation for passthrough
On 09/12/2024 20.29, Matthew Rosato wrote: Specifying this bit in the guest CLP response indicates that the guest can optionally choose to skip translation and instead use identity-mapped operations. Signed-off-by: Matthew Rosato --- hw/s390x/s390-pci-vfio.c| 4 +++- include/hw/s390x/s390-pci-clp.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c index 7dbbc76823..51ac5ff3eb 100644 --- a/hw/s390x/s390-pci-vfio.c +++ b/hw/s390x/s390-pci-vfio.c @@ -224,7 +224,9 @@ static void s390_pci_read_group(S390PCIBusDevice *pbdev, resgrp = &pbdev->pci_group->zpci_group; if (cap->flags & VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH) { -resgrp->fr = 1; +resgrp->fr = (CLP_RSP_QPCIG_MASK_RTR | CLP_RSP_QPCIG_MASK_REFRESH); +} else { +resgrp->fr = CLP_RSP_QPCIG_MASK_RTR; } Just a matter of taste, but maybe easier to write it like this: resgrp->fr = CLP_RSP_QPCIG_MASK_RTR; if (cap->flags & VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH) { resgrp->fr |= CLP_RSP_QPCIG_MASK_REFRESH; } ? Thomas
[PATCH v3 27/69] target/arm: Convert FSQRT (scalar) to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 72 -- target/arm/tcg/a64.decode | 1 + 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 2a5cb70475..f3989246f9 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8344,6 +8344,63 @@ static const FPScalar1Int f_scalar_fneg = { }; TRANS(FNEG_s, do_fp1_scalar_int, a, &f_scalar_fneg) +typedef struct FPScalar1 { +void (*gen_h)(TCGv_i32, TCGv_i32, TCGv_ptr); +void (*gen_s)(TCGv_i32, TCGv_i32, TCGv_ptr); +void (*gen_d)(TCGv_i64, TCGv_i64, TCGv_ptr); +} FPScalar1; + +static bool do_fp1_scalar(DisasContext *s, arg_rr_e *a, + const FPScalar1 *f, int rmode) +{ +TCGv_i32 tcg_rmode = NULL; +TCGv_ptr fpst; +TCGv_i64 t64; +TCGv_i32 t32; +int check = fp_access_check_scalar_hsd(s, a->esz); + +if (check <= 0) { +return check == 0; +} + +fpst = fpstatus_ptr(a->esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR); +if (rmode >= 0) { +tcg_rmode = gen_set_rmode(rmode, fpst); +} + +switch (a->esz) { +case MO_64: +t64 = read_fp_dreg(s, a->rn); +f->gen_d(t64, t64, fpst); +write_fp_dreg(s, a->rd, t64); +break; +case MO_32: +t32 = read_fp_sreg(s, a->rn); +f->gen_s(t32, t32, fpst); +write_fp_sreg(s, a->rd, t32); +break; +case MO_16: +t32 = read_fp_hreg(s, a->rn); +f->gen_h(t32, t32, fpst); +write_fp_sreg(s, a->rd, t32); +break; +default: +g_assert_not_reached(); +} + +if (rmode >= 0) { +gen_restore_rmode(tcg_rmode, fpst); +} +return true; +} + +static const FPScalar1 f_scalar_fsqrt = { +gen_helper_vfp_sqrth, +gen_helper_vfp_sqrts, +gen_helper_vfp_sqrtd, +}; +TRANS(FSQRT_s, do_fp1_scalar, a, &f_scalar_fsqrt, -1) + /* Floating-point data-processing (1 source) - half precision */ static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn) { @@ -8352,10 +8409,6 @@ static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn) TCGv_i32 tcg_res = tcg_temp_new_i32(); switch (opcode) { -case 0x3: /* FSQRT */ -fpst = fpstatus_ptr(FPST_FPCR_F16); -gen_helper_vfp_sqrth(tcg_res, tcg_op, fpst); -break; case 0x8: /* FRINTN */ case 0x9: /* FRINTP */ case 0xa: /* FRINTM */ @@ -8382,6 +8435,7 @@ static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn) case 0x0: /* FMOV */ case 0x1: /* FABS */ case 0x2: /* FNEG */ +case 0x3: /* FSQRT */ g_assert_not_reached(); } @@ -8400,9 +8454,6 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn) tcg_res = tcg_temp_new_i32(); switch (opcode) { -case 0x3: /* FSQRT */ -gen_fpst = gen_helper_vfp_sqrts; -break; case 0x6: /* BFCVT */ gen_fpst = gen_helper_bfcvt; break; @@ -8438,6 +8489,7 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn) case 0x0: /* FMOV */ case 0x1: /* FABS */ case 0x2: /* FNEG */ +case 0x3: /* FSQRT */ g_assert_not_reached(); } @@ -8465,9 +8517,6 @@ static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn) tcg_res = tcg_temp_new_i64(); switch (opcode) { -case 0x3: /* FSQRT */ -gen_fpst = gen_helper_vfp_sqrtd; -break; case 0x8: /* FRINTN */ case 0x9: /* FRINTP */ case 0xa: /* FRINTM */ @@ -8500,6 +8549,7 @@ static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn) case 0x0: /* FMOV */ case 0x1: /* FABS */ case 0x2: /* FNEG */ +case 0x3: /* FSQRT */ g_assert_not_reached(); } @@ -8619,7 +8669,6 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn) goto do_unallocated; } /* fall through */ -case 0x3: case 0x8 ... 0xc: case 0xe ... 0xf: /* 32-to-32 and 64-to-64 ops */ @@ -8672,6 +8721,7 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn) case 0x0: /* FMOV */ case 0x1: /* FABS */ case 0x2: /* FNEG */ +case 0x3: /* FSQRT */ unallocated_encoding(s); break; } diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index b9cc8963da..3b1e8e0776 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -1327,6 +1327,7 @@ FMINV_s 0110 1110 10 11000 0 10 . . @rr_q1e2 FMOV_s 0000 .. 1 00 1 . . @rr_hsd FABS_s 0000 .. 1 01 1 . . @rr_hsd FNEG_s 0000 .. 1 10 1 . . @rr_hsd +FSQRT_s 0000 .. 1 11 1 . . @rr_hsd #
[PATCH v3 43/69] target/arm: Convert handle_rev to decodetree
This includes REV16, REV32, REV64. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 79 +++--- target/arm/tcg/a64.decode | 5 +++ 2 files changed, 10 insertions(+), 74 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 547c6dc5cc..f57b5e2855 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8939,6 +8939,8 @@ TRANS(CMGE0_v, do_gvec_fn2, a, gen_gvec_cge0) TRANS(CMLT0_v, do_gvec_fn2, a, gen_gvec_clt0) TRANS(CMLE0_v, do_gvec_fn2, a, gen_gvec_cle0) TRANS(CMEQ0_v, do_gvec_fn2, a, gen_gvec_ceq0) +TRANS(REV16_v, do_gvec_fn2, a, gen_gvec_rev16) +TRANS(REV32_v, do_gvec_fn2, a, gen_gvec_rev32) static bool do_gvec_fn2_bhs(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) { @@ -8953,6 +8955,7 @@ static bool do_gvec_fn2_bhs(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) TRANS(CLS_v, do_gvec_fn2_bhs, a, gen_gvec_cls) TRANS(CLZ_v, do_gvec_fn2_bhs, a, gen_gvec_clz) +TRANS(REV64_v, do_gvec_fn2_bhs, a, gen_gvec_rev64) /* Common vector code for handling integer to FP conversion */ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, @@ -9882,76 +9885,6 @@ static void handle_2misc_widening(DisasContext *s, int opcode, bool is_q, } } -static void handle_rev(DisasContext *s, int opcode, bool u, - bool is_q, int size, int rn, int rd) -{ -int op = (opcode << 1) | u; -int opsz = op + size; -int grp_size = 3 - opsz; -int dsize = is_q ? 128 : 64; -int i; - -if (opsz >= 3) { -unallocated_encoding(s); -return; -} - -if (!fp_access_check(s)) { -return; -} - -if (size == 0) { -/* Special case bytes, use bswap op on each group of elements */ -int groups = dsize / (8 << grp_size); - -for (i = 0; i < groups; i++) { -TCGv_i64 tcg_tmp = tcg_temp_new_i64(); - -read_vec_element(s, tcg_tmp, rn, i, grp_size); -switch (grp_size) { -case MO_16: -tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp, TCG_BSWAP_IZ); -break; -case MO_32: -tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp, TCG_BSWAP_IZ); -break; -case MO_64: -tcg_gen_bswap64_i64(tcg_tmp, tcg_tmp); -break; -default: -g_assert_not_reached(); -} -write_vec_element(s, tcg_tmp, rd, i, grp_size); -} -clear_vec_high(s, is_q, rd); -} else { -int revmask = (1 << grp_size) - 1; -int esize = 8 << size; -int elements = dsize / esize; -TCGv_i64 tcg_rn = tcg_temp_new_i64(); -TCGv_i64 tcg_rd[2]; - -for (i = 0; i < 2; i++) { -tcg_rd[i] = tcg_temp_new_i64(); -tcg_gen_movi_i64(tcg_rd[i], 0); -} - -for (i = 0; i < elements; i++) { -int e_rev = (i & 0xf) ^ revmask; -int w = (e_rev * esize) / 64; -int o = (e_rev * esize) % 64; - -read_vec_element(s, tcg_rn, rn, i, size); -tcg_gen_deposit_i64(tcg_rd[w], tcg_rd[w], tcg_rn, o, esize); -} - -for (i = 0; i < 2; i++) { -write_vec_element(s, tcg_rd[i], rd, i, MO_64); -} -clear_vec_high(s, true, rd); -} -} - static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u, bool is_q, int size, int rn, int rd) { @@ -10066,10 +,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) TCGv_ptr tcg_fpstatus; switch (opcode) { -case 0x0: /* REV64, REV32 */ -case 0x1: /* REV16 */ -handle_rev(s, opcode, u, is_q, size, rn, rd); -return; case 0x12: /* XTN, XTN2, SQXTUN, SQXTUN2 */ case 0x14: /* SQXTN, SQXTN2, UQXTN, UQXTN2 */ if (size == 3) { @@ -10272,6 +10201,8 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) break; } default: +case 0x0: /* REV64, REV32 */ +case 0x1: /* REV16 */ case 0x3: /* SUQADD, USQADD */ case 0x4: /* CLS, CLZ */ case 0x5: /* CNT, NOT, RBIT */ diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index 247d3a7bda..05f1bc99b5 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -73,6 +73,7 @@ @qrr_b . q:1 .. .. .. .. rn:5 rd:5 &qrr_e esz=0 @qrr_h . q:1 .. .. .. .. rn:5 rd:5 &qrr_e esz=1 +@qrr_bh . q:1 .. . esz:1 .. .. rn:5 rd:5 &qrr_e @qrr_e . q:1 .. esz:2 .. .. rn:5 rd:5 &qrr_e @qrrr_b . q:1 .. ... rm:5 .. rn:5 rd:5 &qrrr_e esz=0 @@ -1657,3 +1658,7 @@ CMGE0_v 0.10 1110 ..1 0 10001 0 . . @qrr_e CMEQ0_v 0.00 1110 ..1 0 10011 0 . . @qrr_e CMLE0_v 0.10 1110 ..1 0
[PULL 18/49] kvm: remove unnecessary #ifdef
Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm_i386.h | 11 +-- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index 9de9c0d3038..7edb154a16e 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -13,8 +13,7 @@ #include "sysemu/kvm.h" -#ifdef CONFIG_KVM - +/* always false if !CONFIG_KVM */ #define kvm_pit_in_kernel() \ (kvm_irqchip_in_kernel() && !kvm_irqchip_is_split()) #define kvm_pic_in_kernel() \ @@ -22,14 +21,6 @@ #define kvm_ioapic_in_kernel() \ (kvm_irqchip_in_kernel() && !kvm_irqchip_is_split()) -#else - -#define kvm_pit_in_kernel() 0 -#define kvm_pic_in_kernel() 0 -#define kvm_ioapic_in_kernel() 0 - -#endif /* CONFIG_KVM */ - bool kvm_has_smm(void); bool kvm_enable_x2apic(void); bool kvm_hv_vpindex_settable(void); -- 2.47.1
[PATCH v2 29/31] tests/functional: remove now unused 'run_cmd' helper
All usage has been replaced by direct 'subprocess' helpers. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/__init__.py | 2 +- tests/functional/qemu_test/cmd.py | 11 --- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py index 3bd043e608..da1830286d 100644 --- a/tests/functional/qemu_test/__init__.py +++ b/tests/functional/qemu_test/__init__.py @@ -8,7 +8,7 @@ from .asset import Asset from .config import BUILD_DIR -from .cmd import run_cmd, is_readable_executable_file, \ +from .cmd import is_readable_executable_file, \ interrupt_interactive_console_until_pattern, wait_for_console_pattern, \ exec_command, exec_command_and_wait_for_pattern, get_qemu_img, which from .testcase import QemuBaseTest, QemuUserTest, QemuSystemTest diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index c8971de00a..dc5f422b77 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -14,7 +14,6 @@ import logging import os import os.path -import subprocess def which(tool): @@ -28,16 +27,6 @@ def which(tool): return p return None -def run_cmd(args): -subp = subprocess.Popen(args, -stdout=subprocess.PIPE, -stderr=subprocess.PIPE, -universal_newlines=True) -stdout, stderr = subp.communicate() -ret = subp.returncode - -return (stdout, stderr, ret) - def is_readable_executable_file(path): return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK) -- 2.46.0
[PATCH v3 68/69] target/arm: Convert URECPE and URSQRTE to decodetree
Remove handle_2misc_reciprocal as these were the last insns decoded by that function. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 139 ++--- target/arm/tcg/a64.decode | 3 + 2 files changed, 8 insertions(+), 134 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 63cf25251b..fa3170da86 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -9163,6 +9163,8 @@ TRANS(CMLE0_v, do_gvec_fn2, a, gen_gvec_cle0) TRANS(CMEQ0_v, do_gvec_fn2, a, gen_gvec_ceq0) TRANS(REV16_v, do_gvec_fn2, a, gen_gvec_rev16) TRANS(REV32_v, do_gvec_fn2, a, gen_gvec_rev32) +TRANS(URECPE_v, do_gvec_fn2, a, gen_gvec_urecpe) +TRANS(URSQRTE_v, do_gvec_fn2, a, gen_gvec_ursqrte) static bool do_gvec_fn2_bhs(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) { @@ -9506,51 +9508,6 @@ static gen_helper_gvec_2_ptr * const f_frsqrte[] = { }; TRANS(FRSQRTE_v, do_gvec_op2_fpst, a->esz, a->q, a->rd, a->rn, 0, f_frsqrte) -static void handle_2misc_reciprocal(DisasContext *s, int opcode, -bool is_scalar, bool is_u, bool is_q, -int size, int rn, int rd) -{ -bool is_double = (size == 3); - -if (is_double) { -g_assert_not_reached(); -} else { -TCGv_i32 tcg_op = tcg_temp_new_i32(); -TCGv_i32 tcg_res = tcg_temp_new_i32(); -int pass, maxpasses; - -if (is_scalar) { -maxpasses = 1; -} else { -maxpasses = is_q ? 4 : 2; -} - -for (pass = 0; pass < maxpasses; pass++) { -read_vec_element_i32(s, tcg_op, rn, pass, MO_32); - -switch (opcode) { -case 0x3c: /* URECPE */ -gen_helper_recpe_u32(tcg_res, tcg_op); -break; -case 0x3d: /* FRECPE */ -case 0x3f: /* FRECPX */ -case 0x7d: /* FRSQRTE */ -default: -g_assert_not_reached(); -} - -if (is_scalar) { -write_fp_sreg(s, rd, tcg_res); -} else { -write_vec_element_i32(s, tcg_res, rd, pass, MO_32); -} -} -if (!is_scalar) { -clear_vec_high(s, is_q, rd); -} -} -} - static void handle_2misc_widening(DisasContext *s, int opcode, bool is_q, int size, int rn, int rd) { @@ -9609,10 +9566,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) bool is_q = extract32(insn, 30, 1); int rn = extract32(insn, 5, 5); int rd = extract32(insn, 0, 5); -bool need_fpstatus = false; -int rmode = -1; -TCGv_i32 tcg_rmode; -TCGv_ptr tcg_fpstatus; switch (opcode) { case 0xc ... 0xf: @@ -9625,28 +9578,12 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) opcode |= (extract32(size, 1, 1) << 5) | (u << 6); size = is_double ? 3 : 2; switch (opcode) { -case 0x3c: /* URECPE */ -if (size == 3) { -unallocated_encoding(s); -return; -} -if (!fp_access_check(s)) { -return; -} -handle_2misc_reciprocal(s, opcode, false, u, is_q, size, rn, rd); -return; case 0x17: /* FCVTL, FCVTL2 */ if (!fp_access_check(s)) { return; } handle_2misc_widening(s, opcode, is_q, size, rn, rd); return; -case 0x7c: /* URSQRTE */ -if (size == 3) { -unallocated_encoding(s); -return; -} -break; default: case 0x16: /* FCVTN, FCVTN2 */ case 0x36: /* BFCVTN, BFCVTN2 */ @@ -9684,6 +9621,8 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) case 0x6d: /* FCMLE (zero) */ case 0x3d: /* FRECPE */ case 0x7d: /* FRSQRTE */ +case 0x3c: /* URECPE */ +case 0x7c: /* URSQRTE */ unallocated_encoding(s); return; } @@ -9708,75 +9647,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) unallocated_encoding(s); return; } - -if (!fp_access_check(s)) { -return; -} - -if (need_fpstatus || rmode >= 0) { -tcg_fpstatus = fpstatus_ptr(FPST_FPCR); -} else { -tcg_fpstatus = NULL; -} -if (rmode >= 0) { -tcg_rmode = gen_set_rmode(rmode, tcg_fpstatus); -} else { -tcg_rmode = NULL; -} - -{ -int pass; - -assert(size == 2); -for (pass = 0; pass < (is_q ? 4 : 2); pass++) { -TCGv_i32 tcg_op = tcg_temp_new_i32(); -TCGv_i32 tcg_res = tcg_temp_new_i32(); - -read_vec_element_i32(s, tcg_op, rn, pass, MO_32); - -{ -
[PATCH v3 59/69] target/arm: Convert [US]CVTF (vector, integer) scalar to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 35 -- target/arm/tcg/a64.decode | 6 ++ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 894befef4d..6e9d040ebf 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8599,6 +8599,29 @@ static bool do_cvtf_g(DisasContext *s, arg_fcvt *a, bool is_signed) TRANS(SCVTF_g, do_cvtf_g, a, true) TRANS(UCVTF_g, do_cvtf_g, a, false) +/* + * [US]CVTF (vector), scalar version. + * Which sounds weird, but really just means input from fp register + * instead of input from general register. Input and output element + * size are always equal. + */ +static bool do_cvtf_f(DisasContext *s, arg_fcvt *a, bool is_signed) +{ +TCGv_i64 tcg_int; +int check = fp_access_check_scalar_hsd(s, a->esz); + +if (check <= 0) { +return check == 0; +} + +tcg_int = tcg_temp_new_i64(); +read_vec_element(s, tcg_int, a->rn, 0, a->esz | (is_signed ? MO_SIGN : 0)); +return do_cvtf_scalar(s, a->esz, a->rd, a->shift, tcg_int, is_signed); +} + +TRANS(SCVTF_f, do_cvtf_f, a, true) +TRANS(UCVTF_f, do_cvtf_f, a, false) + static void do_fcvt_scalar(DisasContext *s, MemOp out, MemOp esz, TCGv_i64 tcg_out, int shift, int rn, ARMFPRounding rmode) @@ -9838,16 +9861,6 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) case 0x6d: /* FCMLE (zero) */ handle_2misc_fcmp_zero(s, opcode, true, u, true, size, rn, rd); return; -case 0x1d: /* SCVTF */ -case 0x5d: /* UCVTF */ -{ -bool is_signed = (opcode == 0x1d); -if (!fp_access_check(s)) { -return; -} -handle_simd_intfp_conv(s, rd, rn, 1, is_signed, 0, size); -return; -} case 0x3d: /* FRECPE */ case 0x3f: /* FRECPX */ case 0x7d: /* FRSQRTE */ @@ -9867,6 +9880,8 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) case 0x1c: /* FCVTAS */ case 0x5c: /* FCVTAU */ case 0x56: /* FCVTXN, FCVTXN2 */ +case 0x1d: /* SCVTF */ +case 0x5d: /* UCVTF */ default: unallocated_encoding(s); return; diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index f66f62da4f..146500d9c4 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -1657,6 +1657,12 @@ FCVTXN_s0111 1110 011 1 01101 0 . . @rr_s @icvt_sd. ... .. .. .. rn:5 rd:5 \ &fcvt sf=0 esz=%esz_sd shift=0 +SCVTF_f 0101 1110 011 11001 11011 0 . . @icvt_h +SCVTF_f 0101 1110 0.1 1 11011 0 . . @icvt_sd + +UCVTF_f 0111 1110 011 11001 11011 0 . . @icvt_h +UCVTF_f 0111 1110 0.1 1 11011 0 . . @icvt_sd + FCVTNS_f0101 1110 011 11001 10101 0 . . @icvt_h FCVTNS_f0101 1110 0.1 1 10101 0 . . @icvt_sd FCVTNU_f0111 1110 011 11001 10101 0 . . @icvt_h -- 2.43.0
[PULL 39/49] rust: add bindings for interrupt sources
The InterruptSource bindings let us call qemu_set_irq() and sysbus_init_irq() as safe code. Interrupt sources, qemu_irq in C code, are pointers to IRQState objects. They are QOM link properties and can be written to outside the control of the device (i.e. from a shared reference); therefore they must be interior-mutable in Rust. Since thread-safety is provided by the BQL, what we want here is the newly-introduced BqlCell. A pointer to the contents of the BqlCell (an IRQState**, or equivalently qemu_irq*) is then passed to the C sysbus_init_irq function. Signed-off-by: Paolo Bonzini --- rust/hw/char/pl011/src/device.rs | 22 rust/qemu-api/meson.build| 2 + rust/qemu-api/src/irq.rs | 91 rust/qemu-api/src/lib.rs | 2 + rust/qemu-api/src/sysbus.rs | 27 ++ 5 files changed, 134 insertions(+), 10 deletions(-) create mode 100644 rust/qemu-api/src/irq.rs create mode 100644 rust/qemu-api/src/sysbus.rs diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 317a9b3c5ad..c5c8c463d37 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -13,6 +13,7 @@ c_str, definitions::ObjectImpl, device_class::TYPE_SYS_BUS_DEVICE, +irq::InterruptSource, }; use crate::{ @@ -94,7 +95,7 @@ pub struct PL011State { /// * sysbus IRQ 5: `UARTEINTR` (error interrupt line) /// ``` #[doc(alias = "irq")] -pub interrupts: [qemu_irq; 6usize], +pub interrupts: [InterruptSource; IRQMASK.len()], #[doc(alias = "clk")] pub clock: NonNull, #[doc(alias = "migrate_clk")] @@ -139,7 +140,8 @@ impl PL011State { unsafe fn init(&mut self) { const CLK_NAME: &CStr = c_str!("clk"); -let dev = addr_of_mut!(*self).cast::(); +let sbd = unsafe { &mut *(addr_of_mut!(*self).cast::()) }; + // SAFETY: // // self and self.iomem are guaranteed to be valid at this point since callers @@ -153,12 +155,15 @@ unsafe fn init(&mut self) { Self::TYPE_INFO.name, 0x1000, ); -let sbd = addr_of_mut!(*self).cast::(); sysbus_init_mmio(sbd, addr_of_mut!(self.iomem)); -for irq in self.interrupts.iter_mut() { -sysbus_init_irq(sbd, irq); -} } + +for irq in self.interrupts.iter() { +sbd.init_irq(irq); +} + +let dev = addr_of_mut!(*self).cast::(); + // SAFETY: // // self.clock is not initialized at this point; but since `NonNull<_>` is Copy, @@ -498,10 +503,7 @@ pub fn put_fifo(&mut self, value: c_uint) { pub fn update(&self) { let flags = self.int_level & self.int_enabled; for (irq, i) in self.interrupts.iter().zip(IRQMASK) { -// SAFETY: self.interrupts have been initialized in init(). -unsafe { -qemu_set_irq(*irq, i32::from(flags & i != 0)); -} +irq.set(flags & i != 0); } } diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index f8b4cd39a26..b927eb58c8e 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -20,8 +20,10 @@ _qemu_api_rs = static_library( 'src/c_str.rs', 'src/definitions.rs', 'src/device_class.rs', + 'src/irq.rs', 'src/offset_of.rs', 'src/prelude.rs', + 'src/sysbus.rs', 'src/vmstate.rs', 'src/zeroable.rs', ], diff --git a/rust/qemu-api/src/irq.rs b/rust/qemu-api/src/irq.rs new file mode 100644 index 000..6258141bdf0 --- /dev/null +++ b/rust/qemu-api/src/irq.rs @@ -0,0 +1,91 @@ +// Copyright 2024 Red Hat, Inc. +// Author(s): Paolo Bonzini +// SPDX-License-Identifier: GPL-2.0-or-later + +//! Bindings for interrupt sources + +use core::ptr; +use std::{marker::PhantomData, os::raw::c_int}; + +use crate::{ +bindings::{qemu_set_irq, IRQState}, +prelude::*, +}; + +/// Interrupt sources are used by devices to pass changes to a value (typically +/// a boolean). The interrupt sink is usually an interrupt controller or +/// GPIO controller. +/// +/// As far as devices are concerned, interrupt sources are always active-high: +/// for example, `InterruptSource`'s [`raise`](InterruptSource::raise) +/// method sends a `true` value to the sink. If the guest has to see a +/// different polarity, that change is performed by the board between the +/// device and the interrupt controller. +/// +/// Interrupts are implemented as a pointer to the interrupt "sink", which has +/// type [`IRQState`]. A device exposes its source as a QOM link property using +/// a function such as +/// [`SysBusDevice::init_irq`](crate::sysbus::SysBusDevice::init_irq), and +/// initially leaves the pointer to a NULL value, representing an unconnected +/// interrupt. To connect it, whoever creates the device fills the pointer with +/// the si
[PATCH v2 00/31] tests/functional: various improvements wrt assets/scratch files
This series is an attempt to bring a little more guaranteed order to asset and scratch file handling in the functional tests. The main highlights are: * Add custom @skipX decorators for common scenarios present in QEMU tests * Add helpers for creating file paths for various well known types of data, or well known locations, to avoid adhoc path manipulation * Add helpers to simplify uncompressing and extracting archives, from files downloaded as assets The series overall has a neutral diffstat, but if you look at just test files, as opposed to the shared infra, you'll see a significant reduction of lines of code in the tests, and I believe its easier to read them with less boilerplate. This is based on: https://gitlab.com/thuth/qemu.git tags/pull-request-2024-12-11 Changes in v2: * Put archive & uncompress helpers in their own files * Have archive_extract & uncompress directly handle assets and format detection * Drop has_cmd/has_cmds helpers in favour of 'which' * Drop obsolete tessract version check * Simplify 'which' impl * Replace 'run_cmd' with direct use of subprocess * Remove even more unused imports * Gracefully handle asset download failure by skipping tests * Drop redundant hardcoded ./contrib path in virtio GPU test * Various docs improvements to decorators * Drop formatting change to import statements Daniel P. Berrangé (31): tests/functional: remove many unused imports tests/functional: resolve str(Asset) to cache file path tests/functional: remove duplicated 'which' function impl tests/functional: simplify 'which' implementation tests/functional: drop 'tesseract_available' helper tests/functional: introduce some helpful decorators tests/functional: switch to new test skip decorators tests/functional: drop 'has_cmd' and 'has_cmds' helpers tests/functional: add helpers for building file paths tests/functional: switch over to using self.log_file(...) tests/functional: switch over to using self.build_file(...) tests/functional: switch over to using self.data_file(...) tests/functional: switch over to using self.scratch_file() tests/functional: switch over to using self.socket_dir(...) tests/functional: remove redundant 'rmtree' call tests/functional: move archive handling into new archive.py file tests/functional: move uncompress handling into new uncompress.py file tests/functional: add common zip_extract helper tests/functional: add common deb_extract helper tests/functional: let cpio_extract accept filenames tests/functional: add a generalized archive_extract tests/functional: add 'archive_extract' to QemuBaseTest tests/functional: convert tests to new archive_extract helper tests/functional: add a generalized uncompress helper tests/functional: add 'uncompress' to QemuBaseTest tests/functional: convert tests to new uncompress helper tests/functional: drop back compat imports from utils.py tests/functional: replace 'run_cmd' with subprocess helpers tests/functional: remove now unused 'run_cmd' helper tests/functional: skip tests if assets are not available tests/functional: ignore errors when caching assets, except for 404 tests/functional/qemu_test/__init__.py| 9 +- tests/functional/qemu_test/archive.py | 117 ++ tests/functional/qemu_test/asset.py | 26 ++- tests/functional/qemu_test/cmd.py | 76 ++- tests/functional/qemu_test/decorators.py | 107 + tests/functional/qemu_test/linuxkernel.py | 30 +-- tests/functional/qemu_test/tesseract.py | 21 +- tests/functional/qemu_test/testcase.py| 205 -- tests/functional/qemu_test/tuxruntest.py | 19 +- tests/functional/qemu_test/uncompress.py | 83 +++ tests/functional/qemu_test/utils.py | 45 tests/functional/test_aarch64_aspeed.py | 23 +- tests/functional/test_aarch64_raspi3.py | 9 +- tests/functional/test_aarch64_raspi4.py | 21 +- tests/functional/test_aarch64_sbsaref.py | 12 +- .../functional/test_aarch64_sbsaref_alpine.py | 1 - .../test_aarch64_sbsaref_freebsd.py | 1 - tests/functional/test_aarch64_virt.py | 14 +- tests/functional/test_acpi_bits.py| 124 --- tests/functional/test_alpha_clipper.py| 6 +- tests/functional/test_arm_aspeed.py | 46 ++-- tests/functional/test_arm_bflt.py | 13 +- tests/functional/test_arm_bpim2u.py | 44 ++-- tests/functional/test_arm_canona1100.py | 10 +- tests/functional/test_arm_collie.py | 2 +- tests/functional/test_arm_cubieboard.py | 40 ++-- tests/functional/test_arm_emcraft_sf2.py | 2 +- tests/functional/test_arm_integratorcp.py | 28 +-- tests/functional/test_arm_orangepi.py | 60 +++-- tests/functional/test_arm_raspi2.py | 21 +- tests/functional/test_arm_smdkc210.py | 18 +-
[PATCH v2 07/31] tests/functional: switch to new test skip decorators
This ensures consistency of behaviour across all the tests, and requires that we provide gitlab bug links when marking a test to be skipped due to unreliability. Reviewed-by: Thomas Huth Signed-off-by: Daniel P. Berrangé --- tests/functional/test_acpi_bits.py | 25 +++-- tests/functional/test_arm_aspeed.py | 6 ++--- tests/functional/test_arm_bflt.py| 7 +++-- tests/functional/test_arm_bpim2u.py | 5 ++-- tests/functional/test_arm_cubieboard.py | 5 ++-- tests/functional/test_arm_integratorcp.py| 25 + tests/functional/test_arm_orangepi.py| 8 +++--- tests/functional/test_linux_initrd.py| 7 +++-- tests/functional/test_m68k_nextcube.py | 15 +++ tests/functional/test_mips64el_fuloong2e.py | 4 +-- tests/functional/test_mips64el_loongson3v.py | 8 +++--- tests/functional/test_mips64el_malta.py | 28 +++- tests/functional/test_ppc64_hv.py| 18 +++-- tests/functional/test_ppc_40p.py | 7 ++--- tests/functional/test_rx_gdbsim.py | 5 ++-- tests/functional/test_sh4_r2d.py | 8 +++--- 16 files changed, 61 insertions(+), 120 deletions(-) diff --git a/tests/functional/test_acpi_bits.py b/tests/functional/test_acpi_bits.py index 1e6d082ecb..8763ea0822 100755 --- a/tests/functional/test_acpi_bits.py +++ b/tests/functional/test_acpi_bits.py @@ -32,7 +32,6 @@ """ import os -import platform import re import shutil import subprocess @@ -46,28 +45,13 @@ Sequence, ) from qemu.machine import QEMUMachine -from unittest import skipIf -from qemu_test import QemuSystemTest, Asset, which +from qemu_test import (QemuSystemTest, Asset, skipIfMissingCommands, + skipIfNotMachine) -deps = ["xorriso", "mformat"] # dependent tools needed in the test setup/box. -supported_platforms = ['x86_64'] # supported test platforms. # default timeout of 120 secs is sometimes not enough for bits test. BITS_TIMEOUT = 200 -def missing_deps(): -""" returns True if any of the test dependent tools are absent. -""" -for dep in deps: -if which(dep) is None: -return True -return False - -def supported_platform(): -""" checks if the test is running on a supported platform. -""" -return platform.machine() in supported_platforms - class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods """ A QEMU VM, with isa-debugcon enabled and bits iso passed @@ -110,9 +94,8 @@ def base_args(self): """return the base argument to QEMU binary""" return self._base_args -@skipIf(not supported_platform() or missing_deps(), -'unsupported platform or dependencies (%s) not installed' \ -% ','.join(deps)) +@skipIfMissingCommands("xorriso", "mformat") +@skipIfNotMachine("x86_64") class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attributes """ ACPI and SMBIOS tests using biosbits. diff --git a/tests/functional/test_arm_aspeed.py b/tests/functional/test_arm_aspeed.py index 314201a439..dc4d067eb6 100755 --- a/tests/functional/test_arm_aspeed.py +++ b/tests/functional/test_arm_aspeed.py @@ -13,10 +13,10 @@ from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern -from qemu_test import has_cmd +from qemu_test import skipIfMissingCommands from qemu_test.utils import archive_extract from zipfile import ZipFile -from unittest import skipUnless + class AST1030Machine(LinuxKernelTest): @@ -218,7 +218,7 @@ def test_arm_ast2600_evb_buildroot(self): 'images/ast2600-evb/buildroot-2023.02-tpm/flash.img'), 'a46009ae8a5403a0826d607215e731a8c68d27c14c41e55331706b8f9c7bd997') -@skipUnless(*has_cmd('swtpm')) +@skipIfMissingCommands('swtpm') def test_arm_ast2600_evb_buildroot_tpm(self): self.set_machine('ast2600-evb') diff --git a/tests/functional/test_arm_bflt.py b/tests/functional/test_arm_bflt.py index 281925d11a..9095b08539 100755 --- a/tests/functional/test_arm_bflt.py +++ b/tests/functional/test_arm_bflt.py @@ -10,9 +10,8 @@ import bz2 from qemu_test import QemuUserTest, Asset -from qemu_test import has_cmd +from qemu_test import skipIfMissingCommands, skipUntrustedTest from qemu_test.utils import cpio_extract -from unittest import skipUnless class LoadBFLT(QemuUserTest): @@ -21,8 +20,8 @@ class LoadBFLT(QemuUserTest): ('https://elinux.org/images/5/51/Stm32_mini_rootfs.cpio.bz2'), 'eefb788e4980c9e8d6c9d60ce7d15d4da6bf4fbc6a80f487673824600d5ba9cc') -@skipUnless(*has_cmd('cpio')) -@skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code') +@skipIfMissingCommands('cpio') +@skipUntrustedTest() def test_stm32(self): # See https://elinux.org/STM32#User_Space rootfs_path_bz2 = self.ASSET_ROOTFS.fetch() diff --git a/tests/functional/
[PATCH v2 01/31] tests/functional: remove many unused imports
Identified using 'pylint --disable=all --enable=W0611' Reviewed-by: Thomas Huth Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/asset.py | 1 - tests/functional/qemu_test/tesseract.py | 1 - tests/functional/qemu_test/tuxruntest.py | 3 +-- tests/functional/test_aarch64_aspeed.py | 1 - tests/functional/test_aarch64_sbsaref_alpine.py | 1 - tests/functional/test_aarch64_sbsaref_freebsd.py | 1 - tests/functional/test_acpi_bits.py | 2 -- tests/functional/test_arm_aspeed.py | 1 - tests/functional/test_arm_bpim2u.py | 2 +- tests/functional/test_arm_collie.py | 2 +- tests/functional/test_arm_cubieboard.py | 1 - tests/functional/test_arm_orangepi.py| 2 +- tests/functional/test_arm_smdkc210.py| 3 +-- tests/functional/test_arm_sx1.py | 2 +- tests/functional/test_microblaze_s3adsp1800.py | 1 - tests/functional/test_ppc_amiga.py | 2 +- tests/functional/test_virtio_gpu.py | 1 - tests/lcitool/libvirt-ci | 2 +- 18 files changed, 8 insertions(+), 21 deletions(-) diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py index f126cd5863..559af0351f 100644 --- a/tests/functional/qemu_test/asset.py +++ b/tests/functional/qemu_test/asset.py @@ -9,7 +9,6 @@ import logging import os import stat -import subprocess import sys import unittest import urllib.request diff --git a/tests/functional/qemu_test/tesseract.py b/tests/functional/qemu_test/tesseract.py index db441027b9..ef1833139d 100644 --- a/tests/functional/qemu_test/tesseract.py +++ b/tests/functional/qemu_test/tesseract.py @@ -5,7 +5,6 @@ # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. -import re import logging from . import has_cmd, run_cmd diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py index ab3b27da43..d375f2713b 100644 --- a/tests/functional/qemu_test/tuxruntest.py +++ b/tests/functional/qemu_test/tuxruntest.py @@ -11,10 +11,9 @@ import os import stat -import time from qemu_test import QemuSystemTest -from qemu_test import exec_command, exec_command_and_wait_for_pattern +from qemu_test import exec_command_and_wait_for_pattern from qemu_test import wait_for_console_pattern from qemu_test import has_cmd, run_cmd, get_qemu_img diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed.py index 59916efd71..e196f88537 100644 --- a/tests/functional/test_aarch64_aspeed.py +++ b/tests/functional/test_aarch64_aspeed.py @@ -6,7 +6,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import sys import os from qemu_test import QemuSystemTest, Asset diff --git a/tests/functional/test_aarch64_sbsaref_alpine.py b/tests/functional/test_aarch64_sbsaref_alpine.py index ebc29b2fb5..6dbc90f30e 100755 --- a/tests/functional/test_aarch64_sbsaref_alpine.py +++ b/tests/functional/test_aarch64_sbsaref_alpine.py @@ -12,7 +12,6 @@ from qemu_test import QemuSystemTest, Asset from qemu_test import wait_for_console_pattern -from qemu_test import interrupt_interactive_console_until_pattern from unittest import skipUnless from test_aarch64_sbsaref import fetch_firmware diff --git a/tests/functional/test_aarch64_sbsaref_freebsd.py b/tests/functional/test_aarch64_sbsaref_freebsd.py index 80298dd190..77ba2ba1da 100755 --- a/tests/functional/test_aarch64_sbsaref_freebsd.py +++ b/tests/functional/test_aarch64_sbsaref_freebsd.py @@ -12,7 +12,6 @@ from qemu_test import QemuSystemTest, Asset from qemu_test import wait_for_console_pattern -from qemu_test import interrupt_interactive_console_until_pattern from unittest import skipUnless from test_aarch64_sbsaref import fetch_firmware diff --git a/tests/functional/test_acpi_bits.py b/tests/functional/test_acpi_bits.py index 63e2c5309d..3df9562394 100755 --- a/tests/functional/test_acpi_bits.py +++ b/tests/functional/test_acpi_bits.py @@ -31,14 +31,12 @@ https://gitlab.com/qemu-project/biosbits-bits . """ -import logging import os import platform import re import shutil import subprocess import tarfile -import tempfile import zipfile from pathlib import Path diff --git a/tests/functional/test_arm_aspeed.py b/tests/functional/test_arm_aspeed.py index d88170ac24..314201a439 100755 --- a/tests/functional/test_arm_aspeed.py +++ b/tests/functional/test_arm_aspeed.py @@ -13,7 +13,6 @@ from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern -from qemu_test import interrupt_interactive_console_until_pattern from qemu_test import has_cmd from qemu_test.utils import archive_extract from zipfile import ZipFile diff --git a/tests/functional/test_arm_bpim2u.py b/tests/functional/test_arm_bpim2u.py index 35ea58d46c..c9cf43c147 100755 ---
[PATCH v3 35/69] target/arm: Convert SQABS, SQNEG to decodetree
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 123 + target/arm/tcg/a64.decode | 11 +++ 2 files changed, 89 insertions(+), 45 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 95bb2b1ca9..9bb9668d11 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8817,6 +8817,78 @@ static bool trans_FMOV_xu(DisasContext *s, arg_rr *a) return true; } +typedef struct ENVScalar1 { +NeonGenOneOpEnvFn *gen_bhs[3]; +NeonGenOne64OpEnvFn *gen_d; +} ENVScalar1; + +static bool do_env_scalar1(DisasContext *s, arg_rr_e *a, const ENVScalar1 *f) +{ +if (!fp_access_check(s)) { +return true; +} +if (a->esz == MO_64) { +TCGv_i64 t = read_fp_dreg(s, a->rn); +f->gen_d(t, tcg_env, t); +write_fp_dreg(s, a->rd, t); +} else { +TCGv_i32 t = tcg_temp_new_i32(); + +read_vec_element_i32(s, t, a->rn, 0, a->esz); +f->gen_bhs[a->esz](t, tcg_env, t); +write_fp_sreg(s, a->rd, t); +} +return true; +} + +static bool do_env_vector1(DisasContext *s, arg_qrr_e *a, const ENVScalar1 *f) +{ +if (a->esz == MO_64 && !a->q) { +return false; +} +if (!fp_access_check(s)) { +return true; +} +if (a->esz == MO_64) { +TCGv_i64 t = tcg_temp_new_i64(); + +for (int i = 0; i < 2; ++i) { +read_vec_element(s, t, a->rn, i, MO_64); +f->gen_d(t, tcg_env, t); +write_vec_element(s, t, a->rd, i, MO_64); +} +} else { +TCGv_i32 t = tcg_temp_new_i32(); +int n = (a->q ? 16 : 8) >> a->esz; + +for (int i = 0; i < n; ++i) { +read_vec_element_i32(s, t, a->rn, i, a->esz); +f->gen_bhs[a->esz](t, tcg_env, t); +write_vec_element_i32(s, t, a->rd, i, a->esz); +} +} +clear_vec_high(s, a->q, a->rd); +return true; +} + +static const ENVScalar1 f_scalar_sqabs = { +{ gen_helper_neon_qabs_s8, + gen_helper_neon_qabs_s16, + gen_helper_neon_qabs_s32 }, +gen_helper_neon_qabs_s64, +}; +TRANS(SQABS_s, do_env_scalar1, a, &f_scalar_sqabs) +TRANS(SQABS_v, do_env_vector1, a, &f_scalar_sqabs) + +static const ENVScalar1 f_scalar_sqneg = { +{ gen_helper_neon_qneg_s8, + gen_helper_neon_qneg_s16, + gen_helper_neon_qneg_s32 }, +gen_helper_neon_qneg_s64, +}; +TRANS(SQNEG_s, do_env_scalar1, a, &f_scalar_sqneg) +TRANS(SQNEG_v, do_env_vector1, a, &f_scalar_sqneg) + /* Common vector code for handling integer to FP conversion */ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, int elements, int is_signed, @@ -9129,13 +9201,6 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, */ tcg_gen_not_i64(tcg_rd, tcg_rn); break; -case 0x7: /* SQABS, SQNEG */ -if (u) { -gen_helper_neon_qneg_s64(tcg_rd, tcg_env, tcg_rn); -} else { -gen_helper_neon_qabs_s64(tcg_rd, tcg_env, tcg_rn); -} -break; case 0xa: /* CMLT */ cond = TCG_COND_LT; do_cmop: @@ -9198,6 +9263,7 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, gen_helper_frint64_d(tcg_rd, tcg_rn, tcg_fpstatus); break; default: +case 0x7: /* SQABS, SQNEG */ g_assert_not_reached(); } } @@ -9540,8 +9606,6 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) TCGv_ptr tcg_fpstatus; switch (opcode) { -case 0x7: /* SQABS / SQNEG */ -break; case 0xa: /* CMLT */ if (u) { unallocated_encoding(s); @@ -9640,6 +9704,7 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) break; default: case 0x3: /* USQADD / SUQADD */ +case 0x7: /* SQABS / SQNEG */ unallocated_encoding(s); return; } @@ -9669,18 +9734,6 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) read_vec_element_i32(s, tcg_rn, rn, 0, size); switch (opcode) { -case 0x7: /* SQABS, SQNEG */ -{ -NeonGenOneOpEnvFn *genfn; -static NeonGenOneOpEnvFn * const fns[3][2] = { -{ gen_helper_neon_qabs_s8, gen_helper_neon_qneg_s8 }, -{ gen_helper_neon_qabs_s16, gen_helper_neon_qneg_s16 }, -{ gen_helper_neon_qabs_s32, gen_helper_neon_qneg_s32 }, -}; -genfn = fns[size][u]; -genfn(tcg_rd, tcg_env, tcg_rn); -break; -} case 0x1a: /* FCVTNS */ case 0x1b: /* FCVTMS */ case 0x1c: /* FCVTAS */ @@ -9698,6 +9751,7 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) tcg_fpstatus); break; default: +
[PATCH v2 03/31] tests/functional: remove duplicated 'which' function impl
Put the 'which' function into shared code. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/__init__.py | 2 +- tests/functional/qemu_test/cmd.py | 10 ++ tests/functional/test_acpi_bits.py | 13 + tests/functional/test_ppc64_hv.py | 13 + 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py index 67f87be9c4..8fbe67 100644 --- a/tests/functional/qemu_test/__init__.py +++ b/tests/functional/qemu_test/__init__.py @@ -10,6 +10,6 @@ from .config import BUILD_DIR from .cmd import has_cmd, has_cmds, run_cmd, is_readable_executable_file, \ interrupt_interactive_console_until_pattern, wait_for_console_pattern, \ -exec_command, exec_command_and_wait_for_pattern, get_qemu_img +exec_command, exec_command_and_wait_for_pattern, get_qemu_img, which from .testcase import QemuBaseTest, QemuUserTest, QemuSystemTest from .linuxkernel import LinuxKernelTest diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index 11c8334a7c..4106f1ee7c 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -18,6 +18,16 @@ from .config import BUILD_DIR +def which(tool): +""" looks up the full path for @tool, returns None if not found +or if @tool does not have executable permissions. +""" +paths=os.getenv('PATH') +for p in paths.split(os.path.pathsep): +p = os.path.join(p, tool) +if os.path.exists(p) and os.access(p, os.X_OK): +return p +return None def has_cmd(name, args=None): """ diff --git a/tests/functional/test_acpi_bits.py b/tests/functional/test_acpi_bits.py index 3df9562394..1e6d082ecb 100755 --- a/tests/functional/test_acpi_bits.py +++ b/tests/functional/test_acpi_bits.py @@ -47,7 +47,7 @@ ) from qemu.machine import QEMUMachine from unittest import skipIf -from qemu_test import QemuSystemTest, Asset +from qemu_test import QemuSystemTest, Asset, which deps = ["xorriso", "mformat"] # dependent tools needed in the test setup/box. supported_platforms = ['x86_64'] # supported test platforms. @@ -55,17 +55,6 @@ # default timeout of 120 secs is sometimes not enough for bits test. BITS_TIMEOUT = 200 -def which(tool): -""" looks up the full path for @tool, returns None if not found -or if @tool does not have executable permissions. -""" -paths=os.getenv('PATH') -for p in paths.split(os.path.pathsep): -p = os.path.join(p, tool) -if os.path.exists(p) and os.access(p, os.X_OK): -return p -return None - def missing_deps(): """ returns True if any of the test dependent tools are absent. """ diff --git a/tests/functional/test_ppc64_hv.py b/tests/functional/test_ppc64_hv.py index d97b62e364..7c6f8234f5 100755 --- a/tests/functional/test_ppc64_hv.py +++ b/tests/functional/test_ppc64_hv.py @@ -11,7 +11,7 @@ from unittest import skipIf, skipUnless from qemu_test import QemuSystemTest, Asset -from qemu_test import wait_for_console_pattern, exec_command +from qemu_test import wait_for_console_pattern, exec_command, which import os import time import subprocess @@ -19,17 +19,6 @@ deps = ["xorriso"] # dependent tools needed in the test setup/box. -def which(tool): -""" looks up the full path for @tool, returns None if not found -or if @tool does not have executable permissions. -""" -paths=os.getenv('PATH') -for p in paths.split(os.path.pathsep): -p = os.path.join(p, tool) -if os.path.exists(p) and os.access(p, os.X_OK): -return p -return None - def missing_deps(): """ returns True if any of the test dependent tools are absent. """ -- 2.46.0
[PATCH v2 26/31] tests/functional: convert tests to new uncompress helper
Replace use of lzma_uncompress and gzip_uncompress with the new uncompress helper. Signed-off-by: Daniel P. Berrangé --- tests/functional/test_aarch64_raspi4.py | 5 + tests/functional/test_aarch64_sbsaref.py | 10 +++--- tests/functional/test_alpha_clipper.py| 4 +--- tests/functional/test_arm_bpim2u.py | 13 +++-- tests/functional/test_arm_cubieboard.py | 14 -- tests/functional/test_arm_orangepi.py | 17 - tests/functional/test_arm_raspi2.py | 5 + tests/functional/test_arm_smdkc210.py | 6 ++ tests/functional/test_mips64el_malta.py | 9 ++--- tests/functional/test_mips_malta.py | 5 + tests/functional/test_mipsel_malta.py | 15 +-- tests/functional/test_rx_gdbsim.py| 5 + tests/functional/test_s390x_ccw_virtio.py | 6 ++ tests/functional/test_s390x_topology.py | 5 + 14 files changed, 31 insertions(+), 88 deletions(-) diff --git a/tests/functional/test_aarch64_raspi4.py b/tests/functional/test_aarch64_raspi4.py index 3918e35e82..7a4302b0c5 100755 --- a/tests/functional/test_aarch64_raspi4.py +++ b/tests/functional/test_aarch64_raspi4.py @@ -7,7 +7,6 @@ from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern -from qemu_test.utils import gzip_uncompress class Aarch64Raspi4Machine(LinuxKernelTest): @@ -63,9 +62,7 @@ def test_arm_raspi4_initrd(self): member='boot/kernel8.img') dtb_path = self.archive_extract(self.ASSET_KERNEL_20190215, member='boot/bcm2711-rpi-4-b.dtb') -initrd_path_gz = self.ASSET_INITRD.fetch() -initrd_path = self.scratch_file('rootfs.cpio') -gzip_uncompress(initrd_path_gz, initrd_path) +initrd_path = self.uncompress(self.ASSET_INITRD) self.set_machine('raspi4b') self.vm.set_console() diff --git a/tests/functional/test_aarch64_sbsaref.py b/tests/functional/test_aarch64_sbsaref.py index 533ca64407..2d756efdab 100755 --- a/tests/functional/test_aarch64_sbsaref.py +++ b/tests/functional/test_aarch64_sbsaref.py @@ -11,7 +11,7 @@ from qemu_test import QemuSystemTest, Asset from qemu_test import wait_for_console_pattern from qemu_test import interrupt_interactive_console_until_pattern -from qemu_test.utils import lzma_uncompress + def fetch_firmware(test): """ @@ -29,14 +29,10 @@ def fetch_firmware(test): """ # Secure BootRom (TF-A code) -fs0_xz_path = Aarch64SbsarefMachine.ASSET_FLASH0.fetch() -fs0_path = test.scratch_file("SBSA_FLASH0.fd") -lzma_uncompress(fs0_xz_path, fs0_path) +fs0_path = test.uncompress(Aarch64SbsarefMachine.ASSET_FLASH0) # Non-secure rom (UEFI and EFI variables) -fs1_xz_path = Aarch64SbsarefMachine.ASSET_FLASH1.fetch() -fs1_path = test.scratch_file("SBSA_FLASH1.fd") -lzma_uncompress(fs1_xz_path, fs1_path) +fs1_path = test.uncompress(Aarch64SbsarefMachine.ASSET_FLASH1) for path in [fs0_path, fs1_path]: with open(path, "ab+") as fd: diff --git a/tests/functional/test_alpha_clipper.py b/tests/functional/test_alpha_clipper.py index 72cd7b57e6..c5d7181953 100755 --- a/tests/functional/test_alpha_clipper.py +++ b/tests/functional/test_alpha_clipper.py @@ -6,7 +6,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later from qemu_test import LinuxKernelTest, Asset -from qemu_test.utils import gzip_uncompress class AlphaClipperTest(LinuxKernelTest): @@ -20,8 +19,7 @@ def test_alpha_clipper(self): self.set_machine('clipper') kernel_path = self.ASSET_KERNEL.fetch() -uncompressed_kernel = self.scratch_file('vmlinux') -gzip_uncompress(kernel_path, uncompressed_kernel) +uncompressed_kernel = self.uncompress(self.ASSET_KERNEL, format="gz") self.vm.set_console() kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0' diff --git a/tests/functional/test_arm_bpim2u.py b/tests/functional/test_arm_bpim2u.py index 91c56b0930..12cd359746 100755 --- a/tests/functional/test_arm_bpim2u.py +++ b/tests/functional/test_arm_bpim2u.py @@ -10,7 +10,6 @@ from qemu_test import LinuxKernelTest, exec_command_and_wait_for_pattern from qemu_test import Asset, interrupt_interactive_console_until_pattern from qemu_test import skipBigDataTest -from qemu_test.utils import gzip_uncompress, lzma_uncompress from qemu_test.utils import image_pow2ceil_expand @@ -65,9 +64,7 @@ def test_arm_bpim2u_initrd(self): dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' 'sun8i-r40-bananapi-m2-ultra.dtb') dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path) -initrd_path_gz = self.ASSET_INITRD.fetch() -initrd_path = self.scratch_file('rootfs.cpio') -gzip_uncompress(initrd_path_gz, initrd_path) +initrd_path = self.uncompress(self.ASSET
[PATCH v2 18/31] tests/functional: add common zip_extract helper
This mirrors the existing archive_extract and cpio_extract helpers Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/archive.py | 8 1 file changed, 8 insertions(+) diff --git a/tests/functional/qemu_test/archive.py b/tests/functional/qemu_test/archive.py index 9872f08d23..06b66701c0 100644 --- a/tests/functional/qemu_test/archive.py +++ b/tests/functional/qemu_test/archive.py @@ -10,6 +10,7 @@ import os import subprocess import tarfile +import zipfile def tar_extract(archive, dest_dir, member=None): @@ -29,3 +30,10 @@ def cpio_extract(cpio_handle, output_path): input=cpio_handle.read(), stderr=subprocess.DEVNULL) os.chdir(cwd) + +def zip_extract(archive, dest_dir, member=None): +with zipfile.ZipFile(archive, 'r') as zf: +if member: +zf.extract(member=member, path=dest_dir) +else: +zf.extractall(path=dest_dir) -- 2.46.0
Re: [RFC PATCH 5/5] hw/arm/virt-acpi-build: Add IORT RMR regions to handle MSI nested binding
On Wed, Dec 11, 2024 at 09:11:12AM -0400, Jason Gunthorpe wrote: > On Tue, Dec 10, 2024 at 05:28:17PM -0800, Nicolin Chen wrote: > > > I would ideally turn it around and provide that range information to > > > the kernel and totally ignore the SW_MSI reserved region once > > > userspace provides it. > > > > Hmm.. that sounds like a uAPI for vITS range..but yes.. > > It controls the window that the kernel uses to dynamically map the ITS > pages. Can we use SET_OPTION for vITS mapping (non-RMR solution) too? > > So, VMM can GET_OPTION(SW_MSI) for msi_base to extract the > > info from kernel. Likely need a second call for its length? > > Since IOMMU_OPTION only supports one val64 input or output. > > No, just forget about the kernel's SW_MSI region. The VMM uses this > API and overrides it and iommufd completely ignores SW_MSI. > > There is nothing special about the range hard coded into the smmu > driver. OK. We will have SET_OPTION(IOMMU_OPTION_SW_MSI_START) and SET_OPTION(IOMMU_OPTION_SW_MSI_LAST). I think we will need some validation to the range too, although iommufd doesn't have the information about the underlying ITS driver: what if user space sets range to a page size, while the ITS driver requires multiple pages? Thanks Nicolin
[PATCH v3 46/69] target/arm: Convert handle_2misc_pairwise to decodetree
This includes SADDLP, UADDLP, SADALP, UADALP. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/helper-a64.h| 2 - target/arm/tcg/helper-a64.c| 18 target/arm/tcg/translate-a64.c | 84 +++--- target/arm/tcg/a64.decode | 5 ++ 4 files changed, 11 insertions(+), 98 deletions(-) diff --git a/target/arm/tcg/helper-a64.h b/target/arm/tcg/helper-a64.h index f811bb85dc..ac7ca190fa 100644 --- a/target/arm/tcg/helper-a64.h +++ b/target/arm/tcg/helper-a64.h @@ -41,8 +41,6 @@ DEF_HELPER_FLAGS_3(recpsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr) DEF_HELPER_FLAGS_3(rsqrtsf_f16, TCG_CALL_NO_RWG, f16, f16, f16, ptr) DEF_HELPER_FLAGS_3(rsqrtsf_f32, TCG_CALL_NO_RWG, f32, f32, f32, ptr) DEF_HELPER_FLAGS_3(rsqrtsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr) -DEF_HELPER_FLAGS_1(neon_addlp_u8, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_1(neon_addlp_u16, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_2(frecpx_f64, TCG_CALL_NO_RWG, f64, f64, ptr) DEF_HELPER_FLAGS_2(frecpx_f32, TCG_CALL_NO_RWG, f32, f32, ptr) DEF_HELPER_FLAGS_2(frecpx_f16, TCG_CALL_NO_RWG, f16, f16, ptr) diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 9b3c407be3..3de564e0fe 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -306,24 +306,6 @@ float64 HELPER(rsqrtsf_f64)(float64 a, float64 b, void *fpstp) return float64_muladd(a, b, float64_three, float_muladd_halve_result, fpst); } -uint64_t HELPER(neon_addlp_u8)(uint64_t a) -{ -uint64_t tmp; - -tmp = a & 0x00ff00ff00ff00ffULL; -tmp += (a >> 8) & 0x00ff00ff00ff00ffULL; -return tmp; -} - -uint64_t HELPER(neon_addlp_u16)(uint64_t a) -{ -uint64_t tmp; - -tmp = a & 0xULL; -tmp += (a >> 16) & 0xULL; -return tmp; -} - /* Floating-point reciprocal exponent - see FPRecpX in ARM ARM */ uint32_t HELPER(frecpx_f16)(uint32_t a, void *fpstp) { diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index f57b5e2855..717d30dd5b 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8956,6 +8956,10 @@ static bool do_gvec_fn2_bhs(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn) TRANS(CLS_v, do_gvec_fn2_bhs, a, gen_gvec_cls) TRANS(CLZ_v, do_gvec_fn2_bhs, a, gen_gvec_clz) TRANS(REV64_v, do_gvec_fn2_bhs, a, gen_gvec_rev64) +TRANS(SADDLP_v, do_gvec_fn2_bhs, a, gen_gvec_saddlp) +TRANS(UADDLP_v, do_gvec_fn2_bhs, a, gen_gvec_uaddlp) +TRANS(SADALP_v, do_gvec_fn2_bhs, a, gen_gvec_sadalp) +TRANS(UADALP_v, do_gvec_fn2_bhs, a, gen_gvec_uadalp) /* Common vector code for handling integer to FP conversion */ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn, @@ -9885,73 +9889,6 @@ static void handle_2misc_widening(DisasContext *s, int opcode, bool is_q, } } -static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u, - bool is_q, int size, int rn, int rd) -{ -/* Implement the pairwise operations from 2-misc: - * SADDLP, UADDLP, SADALP, UADALP. - * These all add pairs of elements in the input to produce a - * double-width result element in the output (possibly accumulating). - */ -bool accum = (opcode == 0x6); -int maxpass = is_q ? 2 : 1; -int pass; -TCGv_i64 tcg_res[2]; - -if (size == 2) { -/* 32 + 32 -> 64 op */ -MemOp memop = size + (u ? 0 : MO_SIGN); - -for (pass = 0; pass < maxpass; pass++) { -TCGv_i64 tcg_op1 = tcg_temp_new_i64(); -TCGv_i64 tcg_op2 = tcg_temp_new_i64(); - -tcg_res[pass] = tcg_temp_new_i64(); - -read_vec_element(s, tcg_op1, rn, pass * 2, memop); -read_vec_element(s, tcg_op2, rn, pass * 2 + 1, memop); -tcg_gen_add_i64(tcg_res[pass], tcg_op1, tcg_op2); -if (accum) { -read_vec_element(s, tcg_op1, rd, pass, MO_64); -tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_op1); -} -} -} else { -for (pass = 0; pass < maxpass; pass++) { -TCGv_i64 tcg_op = tcg_temp_new_i64(); -NeonGenOne64OpFn *genfn; -static NeonGenOne64OpFn * const fns[2][2] = { -{ gen_helper_neon_addlp_s8, gen_helper_neon_addlp_u8 }, -{ gen_helper_neon_addlp_s16, gen_helper_neon_addlp_u16 }, -}; - -genfn = fns[size][u]; - -tcg_res[pass] = tcg_temp_new_i64(); - -read_vec_element(s, tcg_op, rn, pass, MO_64); -genfn(tcg_res[pass], tcg_op); - -if (accum) { -read_vec_element(s, tcg_op, rd, pass, MO_64); -if (size == 0) { -gen_helper_neon_addl_u16(tcg_res[pass], - tcg_res[pass], tcg_op); -} else { -gen_helper_neon_addl_u32(tcg_res[pass], -
[PATCH v2 17/31] tests/functional: move uncompress handling into new uncompress.py file
More uncompress related code will be added shortly, so having a separate file makes more sense. The utils.py imports the functions from archive.py, so that existing callers don't need to be modified. This avoids redundant code churn until later in the series when all calls will be adapted for other reasons. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/uncompress.py | 36 tests/functional/qemu_test/utils.py | 27 ++ 2 files changed, 38 insertions(+), 25 deletions(-) create mode 100644 tests/functional/qemu_test/uncompress.py diff --git a/tests/functional/qemu_test/uncompress.py b/tests/functional/qemu_test/uncompress.py new file mode 100644 index 00..955170df65 --- /dev/null +++ b/tests/functional/qemu_test/uncompress.py @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Utilities for python-based QEMU tests +# +# Copyright 2024 Red Hat, Inc. +# +# Authors: +# Thomas Huth + +import gzip +import lzma +import os +import shutil + + +def gzip_uncompress(gz_path, output_path): +if os.path.exists(output_path): +return +with gzip.open(gz_path, 'rb') as gz_in: +try: +with open(output_path, 'wb') as raw_out: +shutil.copyfileobj(gz_in, raw_out) +except: +os.remove(output_path) +raise + +def lzma_uncompress(xz_path, output_path): +if os.path.exists(output_path): +return +with lzma.open(xz_path, 'rb') as lzma_in: +try: +with open(output_path, 'wb') as raw_out: +shutil.copyfileobj(lzma_in, raw_out) +except: +os.remove(output_path) +raise diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py index 5ce1c4388e..6b87af4414 100644 --- a/tests/functional/qemu_test/utils.py +++ b/tests/functional/qemu_test/utils.py @@ -8,13 +8,12 @@ # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. -import gzip -import lzma import os -import shutil from .archive import tar_extract as archive_extract from .archive import cpio_extract +from .uncompress import gzip_uncompress +from .uncompress import lzma_uncompress """ Round up to next power of 2 @@ -36,25 +35,3 @@ def image_pow2ceil_expand(path): if size != size_aligned: with open(path, 'ab+') as fd: fd.truncate(size_aligned) - -def gzip_uncompress(gz_path, output_path): -if os.path.exists(output_path): -return -with gzip.open(gz_path, 'rb') as gz_in: -try: -with open(output_path, 'wb') as raw_out: -shutil.copyfileobj(gz_in, raw_out) -except: -os.remove(output_path) -raise - -def lzma_uncompress(xz_path, output_path): -if os.path.exists(output_path): -return -with lzma.open(xz_path, 'rb') as lzma_in: -try: -with open(output_path, 'wb') as raw_out: -shutil.copyfileobj(lzma_in, raw_out) -except: -os.remove(output_path) -raise -- 2.46.0
[PATCH v2 11/31] tests/functional: switch over to using self.build_file(...)
This removes direct access of the 'BUILD_DIR' variable. Reviewed-by: Thomas Huth Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/cmd.py | 5 ++--- tests/functional/qemu_test/testcase.py | 4 ++-- tests/functional/test_aarch64_virt.py | 5 ++--- tests/functional/test_virtio_gpu.py| 11 +++ 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index bebcd46dcf..c8971de00a 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -16,7 +16,6 @@ import os.path import subprocess -from .config import BUILD_DIR def which(tool): """ looks up the full path for @tool, returns None if not found @@ -205,10 +204,10 @@ def get_qemu_img(test): # If qemu-img has been built, use it, otherwise the system wide one # will be used. -qemu_img = os.path.join(BUILD_DIR, 'qemu-img') +qemu_img = test.build_file('qemu-img') if os.path.exists(qemu_img): return qemu_img qemu_img = which('qemu-img') if qemu_img is not None: return qemu_img -test.skipTest(f"qemu-img not found in {BUILD_DIR} or '$PATH'") +test.skipTest(f"qemu-img not found in build dir or '$PATH'") diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 2174fbb155..493938240c 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -133,8 +133,8 @@ def setUp(self, bin_prefix): self.arch = self.qemu_bin.split('-')[-1] self.socketdir = None -self.outputdir = os.path.join(BUILD_DIR, 'tests', 'functional', - self.arch, self.id()) +self.outputdir = self.build_file('tests', 'functional', + self.arch, self.id()) self.workdir = os.path.join(self.outputdir, 'scratch') os.makedirs(self.workdir, exist_ok=True) diff --git a/tests/functional/test_aarch64_virt.py b/tests/functional/test_aarch64_virt.py index c967da41b4..5bc461b482 100755 --- a/tests/functional/test_aarch64_virt.py +++ b/tests/functional/test_aarch64_virt.py @@ -14,7 +14,6 @@ import os import logging -from qemu_test import BUILD_DIR from qemu_test import QemuSystemTest, Asset from qemu_test import exec_command, wait_for_console_pattern from qemu_test import get_qemu_img, run_cmd @@ -54,8 +53,8 @@ def test_alpine_virt_tcg_gic_max(self): "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('-bios', self.build_file('pc-bios', + 'edk2-aarch64-code.fd')) self.vm.add_args("-drive", f"file={iso_path},media=cdrom,format=raw") self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom') diff --git a/tests/functional/test_virtio_gpu.py b/tests/functional/test_virtio_gpu.py index 7654421e6b..630569bff8 100755 --- a/tests/functional/test_virtio_gpu.py +++ b/tests/functional/test_virtio_gpu.py @@ -6,7 +6,6 @@ # later. See the COPYING file in the top-level directory. -from qemu_test import BUILD_DIR from qemu_test import QemuSystemTest, Asset from qemu_test import wait_for_console_pattern from qemu_test import exec_command_and_wait_for_pattern @@ -18,12 +17,8 @@ import subprocess -def pick_default_vug_bin(): -relative_path = "./contrib/vhost-user-gpu/vhost-user-gpu" -if is_readable_executable_file(relative_path): -return relative_path - -bld_dir_path = os.path.join(BUILD_DIR, relative_path) +def pick_default_vug_bin(test): +bld_dir_path = test.build_file(relative_path) if is_readable_executable_file(bld_dir_path): return bld_dir_path @@ -86,7 +81,7 @@ def test_vhost_user_vga_virgl(self): # FIXME: should check presence of vhost-user-gpu, virgl, memfd etc self.require_accelerator('kvm') -vug = pick_default_vug_bin() +vug = pick_default_vug_bin(self) if not vug: self.skipTest("Could not find vhost-user-gpu") -- 2.46.0
[PATCH v2 16/31] tests/functional: move archive handling into new archive.py file
More archive related code will be added shortly, so having a separate file makes more sense. The utils.py imports the functions from archive.py, so that existing callers don't need to be modified. This avoids redundant code churn until later in the series when all calls will be adapted for other reasons. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/archive.py | 31 +++ tests/functional/qemu_test/utils.py | 23 +++- 2 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 tests/functional/qemu_test/archive.py diff --git a/tests/functional/qemu_test/archive.py b/tests/functional/qemu_test/archive.py new file mode 100644 index 00..9872f08d23 --- /dev/null +++ b/tests/functional/qemu_test/archive.py @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Utilities for python-based QEMU tests +# +# Copyright 2024 Red Hat, Inc. +# +# Authors: +# Thomas Huth + +import os +import subprocess +import tarfile + + +def tar_extract(archive, dest_dir, member=None): +with tarfile.open(archive) as tf: +if hasattr(tarfile, 'data_filter'): +tf.extraction_filter = getattr(tarfile, 'data_filter', + (lambda member, path: member)) +if member: +tf.extract(member=member, path=dest_dir) +else: +tf.extractall(path=dest_dir) + +def cpio_extract(cpio_handle, output_path): +cwd = os.getcwd() +os.chdir(output_path) +subprocess.run(['cpio', '-i'], + input=cpio_handle.read(), + stderr=subprocess.DEVNULL) +os.chdir(cwd) diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py index 1bf1c410d5..5ce1c4388e 100644 --- a/tests/functional/qemu_test/utils.py +++ b/tests/functional/qemu_test/utils.py @@ -12,8 +12,9 @@ import lzma import os import shutil -import subprocess -import tarfile + +from .archive import tar_extract as archive_extract +from .archive import cpio_extract """ Round up to next power of 2 @@ -36,16 +37,6 @@ def image_pow2ceil_expand(path): with open(path, 'ab+') as fd: fd.truncate(size_aligned) -def archive_extract(archive, dest_dir, member=None): -with tarfile.open(archive) as tf: -if hasattr(tarfile, 'data_filter'): -tf.extraction_filter = getattr(tarfile, 'data_filter', - (lambda member, path: member)) -if member: -tf.extract(member=member, path=dest_dir) -else: -tf.extractall(path=dest_dir) - def gzip_uncompress(gz_path, output_path): if os.path.exists(output_path): return @@ -67,11 +58,3 @@ def lzma_uncompress(xz_path, output_path): except: os.remove(output_path) raise - -def cpio_extract(cpio_handle, output_path): -cwd = os.getcwd() -os.chdir(output_path) -subprocess.run(['cpio', '-i'], - input=cpio_handle.read(), - stderr=subprocess.DEVNULL) -os.chdir(cwd) -- 2.46.0
[PATCH v2 22/31] tests/functional: add 'archive_extract' to QemuBaseTest
This helper wrappers archive.archive_extract, forcing the use of the scratch directory, to ensure any extracted files are cleaned at test termination. If a specific member is requested, then the path to the extracted file is also returned. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/testcase.py | 32 ++ 1 file changed, 32 insertions(+) diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 493938240c..19fb1d0c07 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -25,6 +25,7 @@ from qemu.machine import QEMUMachine from qemu.utils import kvm_available, tcg_available +from .archive import archive_extract from .asset import Asset from .cmd import run_cmd from .config import BUILD_DIR @@ -39,6 +40,37 @@ class QemuBaseTest(unittest.TestCase): log = None logdir = None +''' +@params archive: filename, Asset, or file-like object to extract +@params format: optional archive format (tar, zip, deb, cpio) +@params sub_dir: optional sub-directory to extract into +@params member: optional member file to limit extraction to + +Extracts @archive into the scratch directory, or a directory beneath +named by @sub_dir. All files are extracted unless @member specifies +a limit. + +If @format is None, heuristics will be applied to guess the format +from the filename or Asset URL. @format must be non-None if @archive +is a file-like object. + +If @member is non-None, returns the fully qualified path to @member +''' +def archive_extract(self, archive, format=None, sub_dir=None, member=None): +self.log.debug(f"Extract {archive} format={format}" + + f"sub_dir={sub_dir} member={member}") +if type(archive) == Asset: +archive.fetch() +if sub_dir is None: +archive_extract(archive, self.scratch_file(), format, member) +else: +archive_extract(archive, self.scratch_file(sub_dir), +format, member) + +if member is not None: +return self.scratch_file(member) +return None + ''' Create a temporary directory suitable for storing UNIX socket paths. -- 2.46.0
[PATCH v2 25/31] tests/functional: add 'uncompress' to QemuBaseTest
This helper wrappers utils.uncompress, forcing the use of the scratch directory, to ensure any uncompressed files are cleaned at test termination. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/testcase.py | 25 + 1 file changed, 25 insertions(+) diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 19fb1d0c07..684c94d45f 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -29,6 +29,7 @@ from .asset import Asset from .cmd import run_cmd from .config import BUILD_DIR +from .uncompress import uncompress class QemuBaseTest(unittest.TestCase): @@ -40,6 +41,30 @@ class QemuBaseTest(unittest.TestCase): log = None logdir = None +''' +@params compressed: filename, Asset, or file-like object to uncompress +@params format: optional compression format (gzip, lzma) + +Uncompresses @compressed into the scratch directory. + +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(self, compressed, format=None): +self.log.debug(f"Uncompress {compressed} format={format}") +if type(compressed) == Asset: +compressed.fetch() + +(name, ext) = os.path.splitext(str(compressed)) +uncompressed = self.scratch_file(os.path.basename(name)) + +uncompress(compressed, uncompressed, format) + +return uncompressed + ''' @params archive: filename, Asset, or file-like object to extract @params format: optional archive format (tar, zip, deb, cpio) -- 2.46.0
[PATCH v2 28/31] tests/functional: replace 'run_cmd' with subprocess helpers
The 'run_cmd' helper is re-implementing a convenient helper that already exists in the form of the 'run' and 'check_call' methods provided by 'subprocess'. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/archive.py| 9 --- tests/functional/qemu_test/tesseract.py | 10 tests/functional/qemu_test/testcase.py | 31 +--- tests/functional/qemu_test/tuxruntest.py | 8 +++--- tests/functional/test_aarch64_virt.py| 6 +++-- tests/functional/test_ppc64_tuxrun.py| 7 -- 6 files changed, 41 insertions(+), 30 deletions(-) diff --git a/tests/functional/qemu_test/archive.py b/tests/functional/qemu_test/archive.py index c439d9413a..c803fdaf6d 100644 --- a/tests/functional/qemu_test/archive.py +++ b/tests/functional/qemu_test/archive.py @@ -14,7 +14,6 @@ import zipfile from .asset import Asset -from .cmd import run_cmd def tar_extract(archive, dest_dir, member=None): @@ -52,9 +51,11 @@ def deb_extract(archive, dest_dir, member=None): cwd = os.getcwd() os.chdir(dest_dir) try: -(stdout, stderr, ret) = run_cmd(['ar', 't', archive]) -file_path = stdout.split()[2] -run_cmd(['ar', 'x', archive, file_path]) +proc = run(['ar', 't', archive], + check=True, capture_output=True, encoding='utf8') +file_path = proc.stdout.split()[2] +check_call(['ar', 'x', archive, file_path], + stdout=DEVNULL, stderr=DEVNULL) tar_extract(file_path, dest_dir, member) finally: os.chdir(cwd) diff --git a/tests/functional/qemu_test/tesseract.py b/tests/functional/qemu_test/tesseract.py index 1b7818090a..ede6c6501e 100644 --- a/tests/functional/qemu_test/tesseract.py +++ b/tests/functional/qemu_test/tesseract.py @@ -6,18 +6,18 @@ # later. See the COPYING file in the top-level directory. import logging +from subprocess import run -from . import run_cmd def tesseract_ocr(image_path, tesseract_args=''): console_logger = logging.getLogger('console') console_logger.debug(image_path) -(stdout, stderr, ret) = run_cmd(['tesseract', image_path, - 'stdout']) -if ret: +proc = run(['tesseract', image_path, 'stdout'], + capture_output=True, encoding='utf8') +if proc.returncode: return None lines = [] -for line in stdout.split('\n'): +for line in proc.stdout.split('\n'): sline = line.strip() if len(sline): console_logger.debug(sline) diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 684c94d45f..7bece8738a 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -16,7 +16,7 @@ from pathlib import Path import pycotap import shutil -import subprocess +from subprocess import run import sys import tempfile import unittest @@ -27,7 +27,6 @@ from .archive import archive_extract from .asset import Asset -from .cmd import run_cmd from .config import BUILD_DIR from .uncompress import uncompress @@ -251,11 +250,11 @@ def add_ldpath(self, ldpath): self._ldpath.append(os.path.abspath(ldpath)) def run_cmd(self, bin_path, args=[]): -return subprocess.run([self.qemu_bin] - + ["-L %s" % ldpath for ldpath in self._ldpath] - + [bin_path] - + args, - text=True, capture_output=True) +return run([self.qemu_bin] + + ["-L %s" % ldpath for ldpath in self._ldpath] + + [bin_path] + + args, + text=True, capture_output=True) class QemuSystemTest(QemuBaseTest): """Facilitates system emulation tests.""" @@ -282,7 +281,9 @@ def setUp(self): def set_machine(self, machinename): # TODO: We should use QMP to get the list of available machines if not self._machinehelp: -self._machinehelp = run_cmd([self.qemu_bin, '-M', 'help'])[0]; +self._machinehelp = run( +[self.qemu_bin, '-M', 'help'], +capture_output=True, check=True, encoding='utf8').stdout if self._machinehelp.find(machinename) < 0: self.skipTest('no support for machine ' + machinename) self.machine = machinename @@ -310,15 +311,17 @@ def require_accelerator(self, accelerator): "available" % accelerator) def require_netdev(self, netdevname): -netdevhelp = run_cmd([self.qemu_bin, - '-M', 'none', '-netdev', 'help'])[0]; -if netdevhelp.find('\n' + netdevname + '\n') < 0: +help = run([self.qemu_bin, +'-M', 'none', '-netdev', 'help'], + capture_output=True, check=True, encoding='utf8').stdout; +if help.find('\n' + netdevname + '\n') < 0:
[PATCH v2 09/31] tests/functional: add helpers for building file paths
Add helper methods that construct paths for * log files - to be preserved at the end of a test * scratch files - to be purged at the end of a test * build files - anything relative to the build root * data files - anything relative to the functional test source root * socket files - a short temporary dir to avoid UNIX socket limits These are to be used instead of direct access to the self.workdir, or self.logdir variables, or any other place where paths are built manually. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/testcase.py | 95 ++ 1 file changed, 95 insertions(+) diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 90ae59eb54..89425b737c 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -13,10 +13,12 @@ import logging import os +from pathlib import Path import pycotap import shutil import subprocess import sys +import tempfile import unittest import uuid @@ -37,9 +39,99 @@ class QemuBaseTest(unittest.TestCase): log = None logdir = None +''' +Create a temporary directory suitable for storing UNIX +socket paths. + +Returns: a tempfile.TemporaryDirectory instance +''' +def socket_dir(self): +if self.socketdir is None: +self.socketdir = tempfile.TemporaryDirectory( +prefix="qemu_func_test_sock_") +return self.socketdir + +''' +@params args list of zero or more subdirectories or file + +Construct a path for accessing a data file located +relative to the source directory that is the root for +functional tests. + +@args may be an empty list to reference the root dir +itself, may be a single element to reference a file in +the root directory, or may be multiple elements to +reference a file nested below. The path components +will be joined using the platform appropriate path +separator. + +Returns: string representing a file path +''' +def data_file(self, *args): +return str(Path(Path(__file__).parent.parent, *args)) + +''' +@params args list of zero or more subdirectories or file + +Construct a path for accessing a data file located +relative to the build directory root. + +@args may be an empty list to reference the build dir +itself, may be a single element to reference a file in +the build directory, or may be multiple elements to +reference a file nested below. The path components +will be joined using the platform appropriate path +separator. + +Returns: string representing a file path +''' +def build_file(self, *args): +return str(Path(BUILD_DIR, *args)) + +''' +@params args list of zero or more subdirectories or file + +Construct a path for accessing/creating a scratch file +located relative to a temporary directory dedicated to +this test case. The directory and its contents will be +purged upon completion of the test. + +@args may be an empty list to reference the scratch dir +itself, may be a single element to reference a file in +the scratch directory, or may be multiple elements to +reference a file nested below. The path components +will be joined using the platform appropriate path +separator. + +Returns: string representing a file path +''' +def scratch_file(self, *args): +return str(Path(self.workdir, *args)) + +''' +@params args list of zero or more subdirectories or file + +Construct a path for accessing/creating a log file +located relative to a temporary directory dedicated to +this test case. The directory and its log files will be +preserved upon completion of the test. + +@args may be an empty list to reference the log dir +itself, may be a single element to reference a file in +the log directory, or may be multiple elements to +reference a file nested below. The path components +will be joined using the platform appropriate path +separator. + +Returns: string representing a file path +''' +def log_file(self, *args): +return str(Path(self.logdir, *args)) + def setUp(self, bin_prefix): self.assertIsNotNone(self.qemu_bin, 'QEMU_TEST_QEMU_BINARY must be set') self.arch = self.qemu_bin.split('-')[-1] +self.socketdir = None self.outputdir = os.path.join(BUILD_DIR, 'tests', 'functional', self.arch, self.id()) @@ -65,6 +157,9 @@ def setUp(self, bin_prefix): def tearDown(self): 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 = None self.machinelog.removeHandler(self._log_fh) self.log.removeHandler(self._log_fh) -- 2.46.0
[PATCH v2 05/31] tests/functional: drop 'tesseract_available' helper
Platforms we target have new enough tesseract that it suffices to merely check if the binary exists. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/tesseract.py | 12 +--- tests/functional/test_m68k_nextcube.py | 8 +++- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/tests/functional/qemu_test/tesseract.py b/tests/functional/qemu_test/tesseract.py index ef1833139d..1b7818090a 100644 --- a/tests/functional/qemu_test/tesseract.py +++ b/tests/functional/qemu_test/tesseract.py @@ -7,17 +7,7 @@ import logging -from . import has_cmd, run_cmd - -def tesseract_available(expected_version): -(has_tesseract, _) = has_cmd('tesseract') -if not has_tesseract: -return False -(stdout, stderr, ret) = run_cmd([ 'tesseract', '--version']) -if ret: -return False -version = stdout.split()[1] -return int(version.split('.')[0]) >= expected_version +from . import run_cmd def tesseract_ocr(image_path, tesseract_args=''): console_logger = logging.getLogger('console') diff --git a/tests/functional/test_m68k_nextcube.py b/tests/functional/test_m68k_nextcube.py index 0124622c40..1022e8f468 100755 --- a/tests/functional/test_m68k_nextcube.py +++ b/tests/functional/test_m68k_nextcube.py @@ -13,7 +13,8 @@ from qemu_test import QemuSystemTest, Asset from unittest import skipUnless -from qemu_test.tesseract import tesseract_available, tesseract_ocr +from qemu_test import has_cmd +from qemu_test.tesseract import tesseract_ocr PIL_AVAILABLE = True try: @@ -53,10 +54,7 @@ def test_bootrom_framebuffer_size(self): self.assertEqual(width, 1120) self.assertEqual(height, 832) -# Tesseract 4 adds a new OCR engine based on LSTM neural networks. The -# new version is faster and more accurate than version 3. The drawback is -# that it is still alpha-level software. -@skipUnless(tesseract_available(4), 'tesseract OCR tool not available') +@skipUnless(*has_cmd('tesseract') 'tesseract OCR tool not available') def test_bootrom_framebuffer_ocr_with_tesseract(self): self.set_machine('next-cube') screenshot_path = os.path.join(self.workdir, "dump.ppm") -- 2.46.0
[PATCH v2 04/31] tests/functional: simplify 'which' implementation
The 'access' check implies the file exists. Signed-off-by: Daniel P. Berrangé --- tests/functional/qemu_test/cmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index 4106f1ee7c..600e0509db 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -25,7 +25,7 @@ def which(tool): paths=os.getenv('PATH') for p in paths.split(os.path.pathsep): p = os.path.join(p, tool) -if os.path.exists(p) and os.access(p, os.X_OK): +if os.access(p, os.X_OK): return p return None -- 2.46.0
[PATCH v3 31/69] target/arm: Convert FCVT (scalar) to decodetree
Remove handle_fp_fcvt and disas_fp_1src as these were the last insns decoded by those functions. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 172 + target/arm/tcg/a64.decode | 7 ++ 2 files changed, 74 insertions(+), 105 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index e48dd308fc..b31a6d4dff 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8443,123 +8443,85 @@ TRANS_FEAT(FRINT64Z_s, aa64_frint, do_fp1_scalar, a, &f_scalar_frint64, FPROUNDING_ZERO) TRANS_FEAT(FRINT64X_s, aa64_frint, do_fp1_scalar, a, &f_scalar_frint64, -1) -static void handle_fp_fcvt(DisasContext *s, int opcode, - int rd, int rn, int dtype, int ntype) +static bool trans_FCVT_s_ds(DisasContext *s, arg_rr *a) { -switch (ntype) { -case 0x0: -{ -TCGv_i32 tcg_rn = read_fp_sreg(s, rn); -if (dtype == 1) { -/* Single to double */ -TCGv_i64 tcg_rd = tcg_temp_new_i64(); -gen_helper_vfp_fcvtds(tcg_rd, tcg_rn, tcg_env); -write_fp_dreg(s, rd, tcg_rd); -} else { -/* Single to half */ -TCGv_i32 tcg_rd = tcg_temp_new_i32(); -TCGv_i32 ahp = get_ahp_flag(); -TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR); +if (fp_access_check(s)) { +TCGv_i32 tcg_rn = read_fp_sreg(s, a->rn); +TCGv_i64 tcg_rd = tcg_temp_new_i64(); -gen_helper_vfp_fcvt_f32_to_f16(tcg_rd, tcg_rn, fpst, ahp); -/* write_fp_sreg is OK here because top half of tcg_rd is zero */ -write_fp_sreg(s, rd, tcg_rd); -} -break; -} -case 0x1: -{ -TCGv_i64 tcg_rn = read_fp_dreg(s, rn); -TCGv_i32 tcg_rd = tcg_temp_new_i32(); -if (dtype == 0) { -/* Double to single */ -gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, tcg_env); -} else { -TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR); -TCGv_i32 ahp = get_ahp_flag(); -/* Double to half */ -gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, fpst, ahp); -/* write_fp_sreg is OK here because top half of tcg_rd is zero */ -} -write_fp_sreg(s, rd, tcg_rd); -break; -} -case 0x3: -{ -TCGv_i32 tcg_rn = read_fp_sreg(s, rn); -TCGv_ptr tcg_fpst = fpstatus_ptr(FPST_FPCR); -TCGv_i32 tcg_ahp = get_ahp_flag(); -tcg_gen_ext16u_i32(tcg_rn, tcg_rn); -if (dtype == 0) { -/* Half to single */ -TCGv_i32 tcg_rd = tcg_temp_new_i32(); -gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp); -write_fp_sreg(s, rd, tcg_rd); -} else { -/* Half to double */ -TCGv_i64 tcg_rd = tcg_temp_new_i64(); -gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp); -write_fp_dreg(s, rd, tcg_rd); -} -break; -} -default: -g_assert_not_reached(); +gen_helper_vfp_fcvtds(tcg_rd, tcg_rn, tcg_env); +write_fp_dreg(s, a->rd, tcg_rd); } +return true; } -/* Floating point data-processing (1 source) - * 31 30 29 28 24 23 22 21 2015 14 10 95 40 - * +---+---+---+---+--+---++---+--+--+ - * | M | 0 | S | 1 1 1 1 0 | type | 1 | opcode | 1 0 0 0 0 | Rn | Rd | - * +---+---+---+---+--+---++---+--+--+ - */ -static void disas_fp_1src(DisasContext *s, uint32_t insn) +static bool trans_FCVT_s_hs(DisasContext *s, arg_rr *a) { -int mos = extract32(insn, 29, 3); -int type = extract32(insn, 22, 2); -int opcode = extract32(insn, 15, 6); -int rn = extract32(insn, 5, 5); -int rd = extract32(insn, 0, 5); +if (fp_access_check(s)) { +TCGv_i32 tmp = read_fp_sreg(s, a->rn); +TCGv_i32 ahp = get_ahp_flag(); +TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR); -if (mos) { -goto do_unallocated; +gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); +/* write_fp_sreg is OK here because top half of result is zero */ +write_fp_sreg(s, a->rd, tmp); } +return true; +} -switch (opcode) { -case 0x4: case 0x5: case 0x7: -{ -/* FCVT between half, single and double precision */ -int dtype = extract32(opcode, 0, 2); -if (type == 2 || dtype == type) { -goto do_unallocated; -} -if (!fp_access_check(s)) { -return; -} +static bool trans_FCVT_s_sd(DisasContext *s, arg_rr *a) +{ +if (fp_access_check(s)) { +TCGv_i64 tcg_rn = read_fp_dreg(s, a->rn); +TCGv_i32 tcg_rd = tcg_temp_new_i32(); -handle_fp_fcvt(s, opcode, rd, rn, dtype, type); -break; +gen_helper_vfp_fcvtsd(tcg_rd, t