[PATCH v2 20/31] tests/functional: let cpio_extract accept filenames

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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()

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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(...)

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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}

2024-12-11 Thread Richard Henderson

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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Daniel P . Berrangé
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(...)

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Peter Maydell
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Paolo Bonzini
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson

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

2024-12-11 Thread Frederic Konrad
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

2024-12-11 Thread Frederic Konrad
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

2024-12-11 Thread Frederic Konrad
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

2024-12-11 Thread Frederic Konrad
>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

2024-12-11 Thread Peter Xu
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

2024-12-11 Thread Peter Xu
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

2024-12-11 Thread Richard Henderson

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

2024-12-11 Thread Peter Xu
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

2024-12-11 Thread Richard Henderson

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

2024-12-11 Thread Daniil Tatianin

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

2024-12-11 Thread Steven Sistare

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

2024-12-11 Thread Richard Henderson

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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Paolo Bonzini
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}

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Paolo Bonzini
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

2024-12-11 Thread Paolo Bonzini
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Paolo Bonzini
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Paolo Bonzini
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

2024-12-11 Thread Richard Henderson
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(...)

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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()

2024-12-11 Thread Paolo Bonzini
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*

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Thomas Huth

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

2024-12-11 Thread Thomas Huth

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

2024-12-11 Thread Peter Xu
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

2024-12-11 Thread Peter Xu
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

2024-12-11 Thread Peter Xu
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

2024-12-11 Thread Peter Xu
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

2024-12-11 Thread Peter Xu
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

2024-12-11 Thread Fabiano Rosas
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

2024-12-11 Thread Thomas Huth

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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Paolo Bonzini
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Paolo Bonzini
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Nicolin Chen
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

2024-12-11 Thread Richard Henderson
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

2024-12-11 Thread Daniel P . Berrangé
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(...)

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Daniel P . Berrangé
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

2024-12-11 Thread Richard Henderson
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

  1   2   3   4   5   >