diff --git a/0002-Fix-crash-when-loading-snapshot-on-inactive-node.patch b/0001-block-Fix-crash-when-loading-snapshot-on-inactive-no.patch similarity index 86% rename from 0002-Fix-crash-when-loading-snapshot-on-inactive-node.patch rename to 0001-block-Fix-crash-when-loading-snapshot-on-inactive-no.patch index 68b84c683b0dbee768a32ae81cce01dba9f494a1..b825cd30c8529f935efe2bd334b5ce81a92a8c6f 100644 --- a/0002-Fix-crash-when-loading-snapshot-on-inactive-node.patch +++ b/0001-block-Fix-crash-when-loading-snapshot-on-inactive-no.patch @@ -1,7 +1,8 @@ -From a629fee99ba2189a7452a212f0a01696a65877ac Mon Sep 17 00:00:00 2001 +From e2e01b3a771faded6fbc87d0eeca9612d3f0447b Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 1 Dec 2023 15:25:18 +0100 -Subject: [PATCH] block: Fix crash when loading snapshot on inactive node +Subject: [PATCH 001/293] block: Fix crash when loading snapshot on inactive + node bdrv_is_read_only() only checks if the node is configured to be read-only eventually, but even if it returns false, writing to the node @@ -32,10 +33,10 @@ Signed-off-by: Michael Tokarev 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block/snapshot.c b/block/snapshot.c -index e22ac3eac63..86e29ca59f9 100644 +index ec8cf48..c4d40e8 100644 --- a/block/snapshot.c +++ b/block/snapshot.c -@@ -190,8 +190,10 @@ static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs) +@@ -196,8 +196,10 @@ bdrv_snapshot_fallback(BlockDriverState *bs) int bdrv_can_snapshot(BlockDriverState *bs) { BlockDriver *drv = bs->drv; @@ -48,5 +49,5 @@ index e22ac3eac63..86e29ca59f9 100644 } -- -GitLab +1.8.3.1 diff --git a/0002-vl-Improve-error-message-for-conflicting-incoming-an.patch b/0002-vl-Improve-error-message-for-conflicting-incoming-an.patch new file mode 100644 index 0000000000000000000000000000000000000000..37e0197f8caef39417cc90414be59a6fa4aeb282 --- /dev/null +++ b/0002-vl-Improve-error-message-for-conflicting-incoming-an.patch @@ -0,0 +1,46 @@ +From 64537ff11f0078bc3d2e63ea36f4a17adb124286 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 1 Dec 2023 15:25:19 +0100 +Subject: [PATCH 002/293] vl: Improve error message for conflicting -incoming + and -loadvm + +Currently, the conflict between -incoming and -loadvm is only detected +when loading the snapshot fails because the image is still inactive for +the incoming migration. This results in a suboptimal error message: + +$ ./qemu-system-x86_64 -hda /tmp/test.qcow2 -loadvm foo -incoming defer +qemu-system-x86_64: Device 'ide0-hd0' is writable but does not support snapshots + +Catch the situation already in qemu_validate_options() to improve the +message: + +$ ./qemu-system-x86_64 -hda /tmp/test.qcow2 -loadvm foo -incoming defer +qemu-system-x86_64: 'incoming' and 'loadvm' options are mutually exclusive + +Signed-off-by: Kevin Wolf +Message-ID: <20231201142520.32255-3-kwolf@redhat.com> +Signed-off-by: Kevin Wolf +(cherry picked from commit 5a7f21efaf99c60614fe1967be1c0f9aa46c526e) +Signed-off-by: Michael Tokarev +--- + system/vl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/system/vl.c b/system/vl.c +index 2bcd9ef..6b87bfa 100644 +--- a/system/vl.c ++++ b/system/vl.c +@@ -2426,6 +2426,10 @@ static void qemu_validate_options(const QDict *machine_opts) + } + } + ++ if (loadvm && incoming) { ++ error_report("'incoming' and 'loadvm' options are mutually exclusive"); ++ exit(EXIT_FAILURE); ++ } + if (loadvm && preconfig_requested) { + error_report("'preconfig' and 'loadvm' options are " + "mutually exclusive"); +-- +1.8.3.1 + diff --git a/0003-iotests-Basic-tests-for-internal-snapshots.patch b/0003-iotests-Basic-tests-for-internal-snapshots.patch new file mode 100644 index 0000000000000000000000000000000000000000..bfcafa2580809bf7000ab7917e2e8430baa4919c --- /dev/null +++ b/0003-iotests-Basic-tests-for-internal-snapshots.patch @@ -0,0 +1,317 @@ +From 11b0730d6085cb78cf207e5be30ef0c3867a6282 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 1 Dec 2023 15:25:20 +0100 +Subject: [PATCH 003/293] iotests: Basic tests for internal snapshots + +We have a few test cases that include tests for corner case aspects of +internal snapshots, but nothing that tests that they actually function +as snapshots or that involves deleting a snapshot. Add a test for this +kind of basic internal snapshot functionality. + +The error cases include a regression test for the crash we just fixed +with snapshot operations on inactive images. + +Signed-off-by: Kevin Wolf +Message-ID: <20231201142520.32255-4-kwolf@redhat.com> +Signed-off-by: Kevin Wolf +(cherry picked from commit bb6e2511eb48539b7dcbcb5f47772e156b9c45d1) +Signed-off-by: Michael Tokarev +--- + tests/qemu-iotests/tests/qcow2-internal-snapshots | 170 +++++++++++++++++++++ + .../tests/qcow2-internal-snapshots.out | 107 +++++++++++++ + 2 files changed, 277 insertions(+) + create mode 100755 tests/qemu-iotests/tests/qcow2-internal-snapshots + create mode 100644 tests/qemu-iotests/tests/qcow2-internal-snapshots.out + +diff --git a/tests/qemu-iotests/tests/qcow2-internal-snapshots b/tests/qemu-iotests/tests/qcow2-internal-snapshots +new file mode 100755 +index 0000000..36523ab +--- /dev/null ++++ b/tests/qemu-iotests/tests/qcow2-internal-snapshots +@@ -0,0 +1,170 @@ ++#!/usr/bin/env bash ++# group: rw quick ++# ++# Test case for internal snapshots in qcow2 ++# ++# Copyright (C) 2023 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# creator ++owner=kwolf@redhat.com ++ ++seq="$(basename $0)" ++echo "QA output created by $seq" ++ ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_test_img ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ../common.rc ++. ../common.filter ++ ++# This tests qcow2-specific low-level functionality ++_supported_fmt qcow2 ++_supported_proto generic ++# Internal snapshots are (currently) impossible with refcount_bits=1, ++# and generally impossible with external data files ++_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file ++ ++IMG_SIZE=64M ++ ++_qemu() ++{ ++ $QEMU -no-shutdown -nographic -monitor stdio -serial none \ ++ -blockdev file,filename="$TEST_IMG",node-name=disk0-file \ ++ -blockdev "$IMGFMT",file=disk0-file,node-name=disk0 \ ++ -object iothread,id=iothread0 \ ++ -device virtio-scsi,iothread=iothread0 \ ++ -device scsi-hd,drive=disk0,share-rw=on \ ++ "$@" 2>&1 |\ ++ _filter_qemu | _filter_hmp | _filter_qemu_io ++} ++ ++_make_test_img $IMG_SIZE ++ ++echo ++echo "=== Write some data, take a snapshot and overwrite part of it ===" ++echo ++ ++{ ++ echo 'qemu-io disk0 "write -P0x11 0 1M"' ++ # Give qemu some time to boot before saving the VM state ++ sleep 0.5 ++ echo "savevm snap0" ++ echo 'qemu-io disk0 "write -P0x22 0 512k"' ++ echo "quit" ++} | _qemu ++ ++echo ++$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size ++_check_test_img ++ ++echo ++echo "=== Verify that loading the snapshot reverts to the old content ===" ++echo ++ ++{ ++ # -loadvm reverted the write from the previous QEMU instance ++ echo 'qemu-io disk0 "read -P0x11 0 1M"' ++ ++ # Verify that it works without restarting QEMU, too ++ echo 'qemu-io disk0 "write -P0x33 512k 512k"' ++ echo "loadvm snap0" ++ echo 'qemu-io disk0 "read -P0x11 0 1M"' ++ ++ # Verify COW by writing a partial cluster ++ echo 'qemu-io disk0 "write -P0x33 63k 2k"' ++ echo 'qemu-io disk0 "read -P0x11 0 63k"' ++ echo 'qemu-io disk0 "read -P0x33 63k 2k"' ++ echo 'qemu-io disk0 "read -P0x11 65k 63k"' ++ ++ # Take a second snapshot ++ echo "savevm snap1" ++ ++ echo "quit" ++} | _qemu -loadvm snap0 ++ ++echo ++$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size ++_check_test_img ++ ++echo ++echo "=== qemu-img snapshot can revert to snapshots ===" ++echo ++ ++$QEMU_IMG snapshot -a snap0 "$TEST_IMG" ++$QEMU_IO -c "read -P0x11 0 1M" "$TEST_IMG" | _filter_qemu_io ++$QEMU_IMG snapshot -a snap1 "$TEST_IMG" ++$QEMU_IO \ ++ -c "read -P0x11 0 63k" \ ++ -c "read -P0x33 63k 2k" \ ++ -c "read -P0x11 65k 63k" \ ++ "$TEST_IMG" | _filter_qemu_io ++ ++echo ++echo "=== Deleting snapshots ===" ++echo ++{ ++ # The active layer stays unaffected by deleting the snapshot ++ echo "delvm snap1" ++ echo 'qemu-io disk0 "read -P0x11 0 63k"' ++ echo 'qemu-io disk0 "read -P0x33 63k 2k"' ++ echo 'qemu-io disk0 "read -P0x11 65k 63k"' ++ ++ echo "quit" ++} | _qemu ++ ++ ++echo ++$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size ++_check_test_img ++ ++echo ++echo "=== Error cases ===" ++echo ++ ++# snap1 should not exist any more ++_qemu -loadvm snap1 ++ ++echo ++{ ++ echo "loadvm snap1" ++ echo "quit" ++} | _qemu ++ ++# Snapshot operations and inactive images are incompatible ++echo ++_qemu -loadvm snap0 -incoming defer ++{ ++ echo "loadvm snap0" ++ echo "delvm snap0" ++ echo "savevm snap1" ++ echo "quit" ++} | _qemu -incoming defer ++ ++# -loadvm and -preconfig are incompatible ++echo ++_qemu -loadvm snap0 -preconfig ++ ++# success, all done ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/tests/qcow2-internal-snapshots.out b/tests/qemu-iotests/tests/qcow2-internal-snapshots.out +new file mode 100644 +index 0000000..438f535 +--- /dev/null ++++ b/tests/qemu-iotests/tests/qcow2-internal-snapshots.out +@@ -0,0 +1,107 @@ ++QA output created by qcow2-internal-snapshots ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 ++ ++=== Write some data, take a snapshot and overwrite part of it === ++ ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) qemu-io disk0 "write -P0x11 0 1M" ++wrote 1048576/1048576 bytes at offset 0 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) savevm snap0 ++(qemu) qemu-io disk0 "write -P0x22 0 512k" ++wrote 524288/524288 bytes at offset 0 ++512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) quit ++ ++Snapshot list: ++ID TAG VM SIZE DATE VM CLOCK ICOUNT ++1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 ++No errors were found on the image. ++ ++=== Verify that loading the snapshot reverts to the old content === ++ ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) qemu-io disk0 "read -P0x11 0 1M" ++read 1048576/1048576 bytes at offset 0 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) qemu-io disk0 "write -P0x33 512k 512k" ++wrote 524288/524288 bytes at offset 524288 ++512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) loadvm snap0 ++(qemu) qemu-io disk0 "read -P0x11 0 1M" ++read 1048576/1048576 bytes at offset 0 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) qemu-io disk0 "write -P0x33 63k 2k" ++wrote 2048/2048 bytes at offset 64512 ++2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) qemu-io disk0 "read -P0x11 0 63k" ++read 64512/64512 bytes at offset 0 ++63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) qemu-io disk0 "read -P0x33 63k 2k" ++read 2048/2048 bytes at offset 64512 ++2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) qemu-io disk0 "read -P0x11 65k 63k" ++read 64512/64512 bytes at offset 66560 ++63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) savevm snap1 ++(qemu) quit ++ ++Snapshot list: ++ID TAG VM SIZE DATE VM CLOCK ICOUNT ++1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 ++2 snap1 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 ++No errors were found on the image. ++ ++=== qemu-img snapshot can revert to snapshots === ++ ++read 1048576/1048576 bytes at offset 0 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 64512/64512 bytes at offset 0 ++63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 2048/2048 bytes at offset 64512 ++2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 64512/64512 bytes at offset 66560 ++63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++=== Deleting snapshots === ++ ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) delvm snap1 ++(qemu) qemu-io disk0 "read -P0x11 0 63k" ++read 64512/64512 bytes at offset 0 ++63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) qemu-io disk0 "read -P0x33 63k 2k" ++read 2048/2048 bytes at offset 64512 ++2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) qemu-io disk0 "read -P0x11 65k 63k" ++read 64512/64512 bytes at offset 66560 ++63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++(qemu) quit ++ ++Snapshot list: ++ID TAG VM SIZE DATE VM CLOCK ICOUNT ++1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 ++No errors were found on the image. ++ ++=== Error cases === ++ ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) QEMU_PROG: Snapshot 'snap1' does not exist in one or more devices ++ ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) loadvm snap1 ++Error: Snapshot 'snap1' does not exist in one or more devices ++(qemu) quit ++ ++QEMU_PROG: 'incoming' and 'loadvm' options are mutually exclusive ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) loadvm snap0 ++Error: Device 'disk0' is writable but does not support snapshots ++(qemu) delvm snap0 ++Error: Device 'disk0' is writable but does not support snapshots ++(qemu) savevm snap1 ++Error: Device 'disk0' is writable but does not support snapshots ++(qemu) quit ++ ++QEMU_PROG: 'preconfig' and 'loadvm' options are mutually exclusive ++*** done +-- +1.8.3.1 + diff --git a/0004-target-riscv-kvm-do-not-use-non-portable-strerrornam.patch b/0004-target-riscv-kvm-do-not-use-non-portable-strerrornam.patch new file mode 100644 index 0000000000000000000000000000000000000000..8ea13a5a1485865d2e0b0dc898b4e56172f24f87 --- /dev/null +++ b/0004-target-riscv-kvm-do-not-use-non-portable-strerrornam.patch @@ -0,0 +1,75 @@ +From 7d6a2ce8cff462e01f59a3cd60294a26bcfe5d1e Mon Sep 17 00:00:00 2001 +From: Natanael Copa +Date: Mon, 18 Dec 2023 17:22:44 +0100 +Subject: [PATCH 004/293] target/riscv/kvm: do not use non-portable + strerrorname_np() + +strerrorname_np is non-portable and breaks building with musl libc. + +Use strerror(errno) instead, like we do other places. + +Cc: qemu-stable@nongnu.org +Fixes: commit 082e9e4a58ba (target/riscv/kvm: improve 'init_multiext_cfg' error msg) +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2041 +Buglink: https://gitlab.alpinelinux.org/alpine/aports/-/issues/15541 +Signed-off-by: Natanael Copa +Reviewed-by: Daniel Henrique Barboza +Signed-off-by: Michael Tokarev +(cherry picked from commit d424db235434b8356c6b2d9420b846c7ddcc83ea) +--- + target/riscv/kvm/kvm-cpu.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c +index 45b6cf1..117e33c 100644 +--- a/target/riscv/kvm/kvm-cpu.c ++++ b/target/riscv/kvm/kvm-cpu.c +@@ -832,9 +832,8 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, + multi_ext_cfg->supported = false; + val = false; + } else { +- error_report("Unable to read ISA_EXT KVM register %s, " +- "error code: %s", multi_ext_cfg->name, +- strerrorname_np(errno)); ++ error_report("Unable to read ISA_EXT KVM register %s: %s", ++ multi_ext_cfg->name, strerror(errno)); + exit(EXIT_FAILURE); + } + } else { +@@ -895,8 +894,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) + * + * Error out if we get any other errno. + */ +- error_report("Error when accessing get-reg-list, code: %s", +- strerrorname_np(errno)); ++ error_report("Error when accessing get-reg-list: %s", ++ strerror(errno)); + exit(EXIT_FAILURE); + } + +@@ -905,8 +904,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) + reglist->n = rl_struct.n; + ret = ioctl(kvmcpu->cpufd, KVM_GET_REG_LIST, reglist); + if (ret) { +- error_report("Error when reading KVM_GET_REG_LIST, code %s ", +- strerrorname_np(errno)); ++ error_report("Error when reading KVM_GET_REG_LIST: %s", ++ strerror(errno)); + exit(EXIT_FAILURE); + } + +@@ -927,9 +926,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) + reg.addr = (uint64_t)&val; + ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { +- error_report("Unable to read ISA_EXT KVM register %s, " +- "error code: %s", multi_ext_cfg->name, +- strerrorname_np(errno)); ++ error_report("Unable to read ISA_EXT KVM register %s: %s", ++ multi_ext_cfg->name, strerror(errno)); + exit(EXIT_FAILURE); + } + +-- +1.8.3.1 + diff --git a/0005-include-ui-rect.h-fix-qemu_rect_init-mis-assignment.patch b/0005-include-ui-rect.h-fix-qemu_rect_init-mis-assignment.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb4a071dea83647c1de517d3e7e7445ec41e20e6 --- /dev/null +++ b/0005-include-ui-rect.h-fix-qemu_rect_init-mis-assignment.patch @@ -0,0 +1,38 @@ +From a331dc62adf6da31565c13c115402f6f21589346 Mon Sep 17 00:00:00 2001 +From: Elen Avan +Date: Fri, 22 Dec 2023 22:17:21 +0300 +Subject: [PATCH 005/293] include/ui/rect.h: fix qemu_rect_init() + mis-assignment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Elen Avan +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2051 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2050 +Fixes: a200d53b1fde "virtio-gpu: replace PIXMAN for region/rect test" +Cc: qemu-stable@nongnu.org +Reviewed-by: Michael Tokarev +Reviewed-by: Marc-André Lureau +Signed-off-by: Michael Tokarev +(cherry picked from commit 9d5b42beb6978dc6219d5dc029c9d453c6b8d503) +--- + include/ui/rect.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/ui/rect.h b/include/ui/rect.h +index 94898f9..68f05d7 100644 +--- a/include/ui/rect.h ++++ b/include/ui/rect.h +@@ -19,7 +19,7 @@ static inline void qemu_rect_init(QemuRect *rect, + uint16_t width, uint16_t height) + { + rect->x = x; +- rect->y = x; ++ rect->y = y; + rect->width = width; + rect->height = height; + } +-- +1.8.3.1 + diff --git a/0006-configure-use-a-native-non-cross-compiler-for-linux-.patch b/0006-configure-use-a-native-non-cross-compiler-for-linux-.patch new file mode 100644 index 0000000000000000000000000000000000000000..55baf0def76905111cfcf48982c93e552168cdc5 --- /dev/null +++ b/0006-configure-use-a-native-non-cross-compiler-for-linux-.patch @@ -0,0 +1,40 @@ +From bb28ee11c2f64a1423e78ad5dfcdbcfa79ceb7d6 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 22 Dec 2023 10:55:43 +0100 +Subject: [PATCH 006/293] configure: use a native non-cross compiler for + linux-user + +Commit c2118e9e1ab ("configure: don't try a "native" cross for linux-user", +2023-11-23) sought to avoid issues with using the native compiler with a +cross-endian or cross-bitness setup. However, in doing so it ended up +requiring a cross compiler setup (and most likely a slow compiler setup) +even when building TCG tests that are native to the host architecture. +Always allow the host compiler in that case. + +Cc: qemu-stable@nongnu.org +Fixes: c2118e9e1ab ("configure: don't try a "native" cross for linux-user", 2023-11-23) +Signed-off-by: Paolo Bonzini +(cherry picked from commit 007531586aa8ef6dccdadd927b89a50af62288d1) +Signed-off-by: Michael Tokarev +--- + configure | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/configure b/configure +index bdda912..d7e0926 100755 +--- a/configure ++++ b/configure +@@ -1387,8 +1387,8 @@ probe_target_compiler() { + done + + try=cross +- # For softmmu/roms we might be able to use the host compiler +- if [ "${1%softmmu}" != "$1" ]; then ++ # For softmmu/roms also look for a bi-endian or multilib-enabled host compiler ++ if [ "${1%softmmu}" != "$1" ] || test "$target_arch" = "$cpu"; then + case "$target_arch:$cpu" in + aarch64_be:aarch64 | \ + armeb:arm | \ +-- +1.8.3.1 + diff --git a/0006-target-loongarch-move-translate-modules-to-tcg.patch b/0006-target-loongarch-move-translate-modules-to-tcg.patch deleted file mode 100644 index 7611ce3e869c306801bcae2bba7d9e16c59c0735..0000000000000000000000000000000000000000 --- a/0006-target-loongarch-move-translate-modules-to-tcg.patch +++ /dev/null @@ -1,215 +0,0 @@ -From eef77dd5b0d292d8a0276c820fc8fee24de0d898 Mon Sep 17 00:00:00 2001 -From: Song Gao -Date: Tue, 2 Jan 2024 10:02:00 +0800 -Subject: [PATCH] target/loongarch: move translate modules to tcg/ -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Introduce the target/loongarch/tcg directory. Its purpose is to hold the TCG -code that is selected by CONFIG_TCG - -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Song Gao -Message-Id: <20240102020200.3462097-2-gaosong@loongson.cn> ---- - target/loongarch/meson.build | 15 +-------------- - target/loongarch/{ => tcg}/constant_timer.c | 0 - target/loongarch/{ => tcg}/csr_helper.c | 0 - target/loongarch/{ => tcg}/fpu_helper.c | 0 - .../{ => tcg}/insn_trans/trans_arith.c.inc | 0 - .../{ => tcg}/insn_trans/trans_atomic.c.inc | 0 - .../{ => tcg}/insn_trans/trans_bit.c.inc | 0 - .../{ => tcg}/insn_trans/trans_branch.c.inc | 0 - .../{ => tcg}/insn_trans/trans_extra.c.inc | 0 - .../{ => tcg}/insn_trans/trans_farith.c.inc | 0 - .../{ => tcg}/insn_trans/trans_fcmp.c.inc | 0 - .../{ => tcg}/insn_trans/trans_fcnv.c.inc | 0 - .../{ => tcg}/insn_trans/trans_fmemory.c.inc | 0 - .../{ => tcg}/insn_trans/trans_fmov.c.inc | 0 - .../{ => tcg}/insn_trans/trans_memory.c.inc | 0 - .../insn_trans/trans_privileged.c.inc | 0 - .../{ => tcg}/insn_trans/trans_shift.c.inc | 0 - .../{ => tcg}/insn_trans/trans_vec.c.inc | 0 - target/loongarch/{ => tcg}/iocsr_helper.c | 0 - target/loongarch/tcg/meson.build | 19 +++++++++++++++++++ - target/loongarch/{ => tcg}/op_helper.c | 0 - target/loongarch/{ => tcg}/tlb_helper.c | 0 - target/loongarch/{ => tcg}/translate.c | 0 - target/loongarch/{ => tcg}/vec_helper.c | 0 - 24 files changed, 20 insertions(+), 14 deletions(-) - rename target/loongarch/{ => tcg}/constant_timer.c (100%) - rename target/loongarch/{ => tcg}/csr_helper.c (100%) - rename target/loongarch/{ => tcg}/fpu_helper.c (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_arith.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_atomic.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_bit.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_branch.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_extra.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_farith.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_fcmp.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_fcnv.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_fmemory.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_fmov.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_memory.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_privileged.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_shift.c.inc (100%) - rename target/loongarch/{ => tcg}/insn_trans/trans_vec.c.inc (100%) - rename target/loongarch/{ => tcg}/iocsr_helper.c (100%) - create mode 100644 target/loongarch/tcg/meson.build - rename target/loongarch/{ => tcg}/op_helper.c (100%) - rename target/loongarch/{ => tcg}/tlb_helper.c (100%) - rename target/loongarch/{ => tcg}/translate.c (100%) - rename target/loongarch/{ => tcg}/vec_helper.c (100%) - -diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build -index b3a0fb12fb..e84e4c51f4 100644 ---- a/target/loongarch/meson.build -+++ b/target/loongarch/meson.build -@@ -5,29 +5,16 @@ loongarch_ss.add(files( - 'cpu.c', - 'gdbstub.c', - )) --loongarch_tcg_ss = ss.source_set() --loongarch_tcg_ss.add(gen) --loongarch_tcg_ss.add(files( -- 'fpu_helper.c', -- 'op_helper.c', -- 'translate.c', -- 'vec_helper.c', --)) --loongarch_tcg_ss.add(zlib) - - loongarch_system_ss = ss.source_set() - loongarch_system_ss.add(files( - 'loongarch-qmp-cmds.c', - 'machine.c', -- 'tlb_helper.c', -- 'constant_timer.c', -- 'csr_helper.c', -- 'iocsr_helper.c', - )) - - common_ss.add(when: 'CONFIG_LOONGARCH_DIS', if_true: [files('disas.c'), gen]) - --loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) -+subdir('tcg') - - target_arch += {'loongarch': loongarch_ss} - target_system_arch += {'loongarch': loongarch_system_ss} -diff --git a/target/loongarch/constant_timer.c b/target/loongarch/tcg/constant_timer.c -similarity index 100% -rename from target/loongarch/constant_timer.c -rename to target/loongarch/tcg/constant_timer.c -diff --git a/target/loongarch/csr_helper.c b/target/loongarch/tcg/csr_helper.c -similarity index 100% -rename from target/loongarch/csr_helper.c -rename to target/loongarch/tcg/csr_helper.c -diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c -similarity index 100% -rename from target/loongarch/fpu_helper.c -rename to target/loongarch/tcg/fpu_helper.c -diff --git a/target/loongarch/insn_trans/trans_arith.c.inc b/target/loongarch/tcg/insn_trans/trans_arith.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_arith.c.inc -rename to target/loongarch/tcg/insn_trans/trans_arith.c.inc -diff --git a/target/loongarch/insn_trans/trans_atomic.c.inc b/target/loongarch/tcg/insn_trans/trans_atomic.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_atomic.c.inc -rename to target/loongarch/tcg/insn_trans/trans_atomic.c.inc -diff --git a/target/loongarch/insn_trans/trans_bit.c.inc b/target/loongarch/tcg/insn_trans/trans_bit.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_bit.c.inc -rename to target/loongarch/tcg/insn_trans/trans_bit.c.inc -diff --git a/target/loongarch/insn_trans/trans_branch.c.inc b/target/loongarch/tcg/insn_trans/trans_branch.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_branch.c.inc -rename to target/loongarch/tcg/insn_trans/trans_branch.c.inc -diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/tcg/insn_trans/trans_extra.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_extra.c.inc -rename to target/loongarch/tcg/insn_trans/trans_extra.c.inc -diff --git a/target/loongarch/insn_trans/trans_farith.c.inc b/target/loongarch/tcg/insn_trans/trans_farith.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_farith.c.inc -rename to target/loongarch/tcg/insn_trans/trans_farith.c.inc -diff --git a/target/loongarch/insn_trans/trans_fcmp.c.inc b/target/loongarch/tcg/insn_trans/trans_fcmp.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_fcmp.c.inc -rename to target/loongarch/tcg/insn_trans/trans_fcmp.c.inc -diff --git a/target/loongarch/insn_trans/trans_fcnv.c.inc b/target/loongarch/tcg/insn_trans/trans_fcnv.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_fcnv.c.inc -rename to target/loongarch/tcg/insn_trans/trans_fcnv.c.inc -diff --git a/target/loongarch/insn_trans/trans_fmemory.c.inc b/target/loongarch/tcg/insn_trans/trans_fmemory.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_fmemory.c.inc -rename to target/loongarch/tcg/insn_trans/trans_fmemory.c.inc -diff --git a/target/loongarch/insn_trans/trans_fmov.c.inc b/target/loongarch/tcg/insn_trans/trans_fmov.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_fmov.c.inc -rename to target/loongarch/tcg/insn_trans/trans_fmov.c.inc -diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/tcg/insn_trans/trans_memory.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_memory.c.inc -rename to target/loongarch/tcg/insn_trans/trans_memory.c.inc -diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_privileged.c.inc -rename to target/loongarch/tcg/insn_trans/trans_privileged.c.inc -diff --git a/target/loongarch/insn_trans/trans_shift.c.inc b/target/loongarch/tcg/insn_trans/trans_shift.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_shift.c.inc -rename to target/loongarch/tcg/insn_trans/trans_shift.c.inc -diff --git a/target/loongarch/insn_trans/trans_vec.c.inc b/target/loongarch/tcg/insn_trans/trans_vec.c.inc -similarity index 100% -rename from target/loongarch/insn_trans/trans_vec.c.inc -rename to target/loongarch/tcg/insn_trans/trans_vec.c.inc -diff --git a/target/loongarch/iocsr_helper.c b/target/loongarch/tcg/iocsr_helper.c -similarity index 100% -rename from target/loongarch/iocsr_helper.c -rename to target/loongarch/tcg/iocsr_helper.c -diff --git a/target/loongarch/tcg/meson.build b/target/loongarch/tcg/meson.build -new file mode 100644 -index 0000000000..1a3cd589fb ---- /dev/null -+++ b/target/loongarch/tcg/meson.build -@@ -0,0 +1,19 @@ -+if 'CONFIG_TCG' not in config_all -+ subdir_done() -+endif -+ -+loongarch_ss.add([zlib, gen]) -+ -+loongarch_ss.add(files( -+ 'fpu_helper.c', -+ 'op_helper.c', -+ 'translate.c', -+ 'vec_helper.c', -+)) -+ -+loongarch_system_ss.add(files( -+ 'constant_timer.c', -+ 'csr_helper.c', -+ 'iocsr_helper.c', -+ 'tlb_helper.c', -+)) -diff --git a/target/loongarch/op_helper.c b/target/loongarch/tcg/op_helper.c -similarity index 100% -rename from target/loongarch/op_helper.c -rename to target/loongarch/tcg/op_helper.c -diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c -similarity index 100% -rename from target/loongarch/tlb_helper.c -rename to target/loongarch/tcg/tlb_helper.c -diff --git a/target/loongarch/translate.c b/target/loongarch/tcg/translate.c -similarity index 100% -rename from target/loongarch/translate.c -rename to target/loongarch/tcg/translate.c -diff --git a/target/loongarch/vec_helper.c b/target/loongarch/tcg/vec_helper.c -similarity index 100% -rename from target/loongarch/vec_helper.c -rename to target/loongarch/tcg/vec_helper.c --- -2.33.0 - diff --git a/0001-sgx-stub-fix.patch b/0007-target-i386-the-sgx_epc_get_section-stub-is-reachabl.patch similarity index 58% rename from 0001-sgx-stub-fix.patch rename to 0007-target-i386-the-sgx_epc_get_section-stub-is-reachabl.patch index ff31973ab889f66c9260ba4b70b4c5cfa041af0a..e85f21b14f63ccb45c520058f761471e7e7c5808 100644 --- a/0001-sgx-stub-fix.patch +++ b/0007-target-i386-the-sgx_epc_get_section-stub-is-reachabl.patch @@ -1,7 +1,8 @@ -From 509b6078631ad2437e1a452f749831e401fb8afb Mon Sep 17 00:00:00 2001 +From e649de10d509026343eb51159bd3791b5f9b11df Mon Sep 17 00:00:00 2001 From: Paolo Bonzini -Date: Tue, 1 Feb 2022 20:09:37 +0100 -Subject: [PATCH] target/i386: the sgx_epc_get_section stub is reachable +Date: Tue, 1 Feb 2022 20:09:41 +0100 +Subject: [PATCH 007/293] target/i386: the sgx_epc_get_section stub is + reachable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -13,9 +14,16 @@ the "real" sgx_epc_get_section does when SGX is disabled. Reported-by: Vladimír Beneš Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini +Message-ID: <20220201190941.106001-1-pbonzini@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 219615740425d9683588207b40a365e6741691a6) +Signed-off-by: Michael Tokarev +--- + hw/i386/sgx-stub.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/sgx-stub.c b/hw/i386/sgx-stub.c -index 26833eb233..16b1dfd90b 100644 +index 26833eb..16b1dfd 100644 --- a/hw/i386/sgx-stub.c +++ b/hw/i386/sgx-stub.c @@ -34,5 +34,5 @@ void pc_machine_init_sgx_epc(PCMachineState *pcms) @@ -25,3 +33,6 @@ index 26833eb233..16b1dfd90b 100644 - g_assert_not_reached(); + return true; } +-- +1.8.3.1 + diff --git a/0008-hw-net-can-sja1000-fix-bug-for-single-acceptance-fil.patch b/0008-hw-net-can-sja1000-fix-bug-for-single-acceptance-fil.patch new file mode 100644 index 0000000000000000000000000000000000000000..cdacf13a75bbacbf8da7c548fc5db27f77fe22d5 --- /dev/null +++ b/0008-hw-net-can-sja1000-fix-bug-for-single-acceptance-fil.patch @@ -0,0 +1,42 @@ +From 7b57e6d4340926b0a24853fb7d805bdaf8503eb2 Mon Sep 17 00:00:00 2001 +From: Pavel Pisa +Date: Thu, 4 Jan 2024 00:14:26 +0100 +Subject: [PATCH 008/293] hw/net/can/sja1000: fix bug for single acceptance + filter and standard frame + +A CAN sja1000 standard frame filter mask has been computed and applied +incorrectly for standard frames when single Acceptance Filter Mode +(MOD_AFM = 1) has been selected. The problem has not been found +by Linux kernel testing because it uses dual filter mode (MOD_AFM = 0) +and leaves falters fully open. + +The problem has been noticed by Grant Ramsay when testing with Zephyr +RTOS which uses single filter mode. + +Signed-off-by: Pavel Pisa +Reported-by: Grant Ramsay +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2028 +Fixes: 733210e754 ("hw/net/can: SJA1000 chip register level emulation") +Message-ID: <20240103231426.5685-1-pisa@fel.cvut.cz> +(cherry picked from commit 25145a7d7735344a469551946fc2a7f19eb4aa3d) +Signed-off-by: Michael Tokarev +--- + hw/net/can/can_sja1000.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c +index 73201f9..575df7d 100644 +--- a/hw/net/can/can_sja1000.c ++++ b/hw/net/can/can_sja1000.c +@@ -108,7 +108,7 @@ void can_sja_single_filter(struct qemu_can_filter *filter, + } + + filter->can_mask = (uint32_t)amr[0] << 3; +- filter->can_mask |= (uint32_t)amr[1] << 5; ++ filter->can_mask |= (uint32_t)amr[1] >> 5; + filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK; + if (!(amr[1] & 0x10)) { + filter->can_mask |= QEMU_CAN_RTR_FLAG; +-- +1.8.3.1 + diff --git a/0009-target-riscv-Fix-mcycle-minstret-increment-behavior.patch b/0009-target-riscv-Fix-mcycle-minstret-increment-behavior.patch new file mode 100644 index 0000000000000000000000000000000000000000..781ec503ea025d3c3bbcec4b8a3d9cb54a8cda81 --- /dev/null +++ b/0009-target-riscv-Fix-mcycle-minstret-increment-behavior.patch @@ -0,0 +1,58 @@ +From 882950efd25c03fe62fd511f184d7ed2da6f33fe Mon Sep 17 00:00:00 2001 +From: Xu Lu +Date: Tue, 26 Dec 2023 12:05:00 +0800 +Subject: [PATCH 009/293] target/riscv: Fix mcycle/minstret increment behavior + +The mcycle/minstret counter's stop flag is mistakenly updated on a copy +on stack. Thus the counter increments even when the CY/IR bit in the +mcountinhibit register is set. This commit corrects its behavior. + +Fixes: 3780e33732f88 (target/riscv: Support mcycle/minstret write operation) +Signed-off-by: Xu Lu +Reviewed-by: Daniel Henrique Barboza +Signed-off-by: Michael Tokarev +(cherry picked from commit 5cb0e7abe1635cb82e0033260dac2b910d142f8c) +Signed-off-by: Michael Tokarev +--- + target/riscv/csr.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/target/riscv/csr.c b/target/riscv/csr.c +index fde7ce1..c50a333 100644 +--- a/target/riscv/csr.c ++++ b/target/riscv/csr.c +@@ -907,11 +907,11 @@ static int write_mhpmcounterh(CPURISCVState *env, int csrno, target_ulong val) + static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, + bool upper_half, uint32_t ctr_idx) + { +- PMUCTRState counter = env->pmu_ctrs[ctr_idx]; +- target_ulong ctr_prev = upper_half ? counter.mhpmcounterh_prev : +- counter.mhpmcounter_prev; +- target_ulong ctr_val = upper_half ? counter.mhpmcounterh_val : +- counter.mhpmcounter_val; ++ PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; ++ target_ulong ctr_prev = upper_half ? counter->mhpmcounterh_prev : ++ counter->mhpmcounter_prev; ++ target_ulong ctr_val = upper_half ? counter->mhpmcounterh_val : ++ counter->mhpmcounter_val; + + if (get_field(env->mcountinhibit, BIT(ctr_idx))) { + /* +@@ -919,12 +919,12 @@ static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, + * stop the icount counting. Just return the counter value written by + * the supervisor to indicate that counter was not incremented. + */ +- if (!counter.started) { ++ if (!counter->started) { + *val = ctr_val; + return RISCV_EXCP_NONE; + } else { + /* Mark that the counter has been stopped */ +- counter.started = false; ++ counter->started = false; + } + } + +-- +1.8.3.1 + diff --git a/0010-chardev-char.c-fix-abstract-device-type-error-messag.patch b/0010-chardev-char.c-fix-abstract-device-type-error-messag.patch new file mode 100644 index 0000000000000000000000000000000000000000..214d9f0be5b1e8c0e8930f5d71aafd13b399a840 --- /dev/null +++ b/0010-chardev-char.c-fix-abstract-device-type-error-messag.patch @@ -0,0 +1,38 @@ +From 0965e5eda5d323a6b390c8bada365f2258bc7ca7 Mon Sep 17 00:00:00 2001 +From: Michael Tokarev +Date: Wed, 3 Jan 2024 14:37:39 +0300 +Subject: [PATCH 010/293] chardev/char.c: fix "abstract device type" error + message + +Current error message: + + qemu-system-x86_64: -chardev spice,id=foo: Parameter 'driver' expects an abstract device type + +while in fact the meaning is in reverse, -chardev expects +a non-abstract device type. + +Fixes: 777357d758d9 ("chardev: qom-ify" 2016-12-07) +Signed-off-by: Michael Tokarev +Reviewed-by: Zhao Liu +(cherry picked from commit 4ad87cd4b2254197b7ac12e3da824854e6a90f8f) +Signed-off-by: Michael Tokarev +--- + chardev/char.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/chardev/char.c b/chardev/char.c +index 996a024..119b548 100644 +--- a/chardev/char.c ++++ b/chardev/char.c +@@ -518,7 +518,7 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp) + + if (object_class_is_abstract(oc)) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver", +- "an abstract device type"); ++ "a non-abstract device type"); + return NULL; + } + +-- +1.8.3.1 + diff --git a/0011-audio-audio.c-remove-trailing-newline-in-error_setg.patch b/0011-audio-audio.c-remove-trailing-newline-in-error_setg.patch new file mode 100644 index 0000000000000000000000000000000000000000..429c5782a2b05b1cd3a59c9393da977147c34a69 --- /dev/null +++ b/0011-audio-audio.c-remove-trailing-newline-in-error_setg.patch @@ -0,0 +1,35 @@ +From 5713d6dd76d2bb10f8e2367512217ef49fe797ed Mon Sep 17 00:00:00 2001 +From: Michael Tokarev +Date: Wed, 3 Jan 2024 14:18:00 +0300 +Subject: [PATCH 011/293] audio/audio.c: remove trailing newline in error_setg +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +error_setg() appends newline to the formatted message. +Fixes: cb94ff5f80c5 ("audio: propagate Error * out of audio_init") + +Signed-off-by: Michael Tokarev +Reviewed-by: Philippe Mathieu-Daudé +(cherry picked from commit 09a36158c283f7448d1b00fdbb6634f05d27f922) +Signed-off-by: Michael Tokarev +--- + audio/audio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/audio/audio.c b/audio/audio.c +index 8d1e4ad..7ac74f9 100644 +--- a/audio/audio.c ++++ b/audio/audio.c +@@ -1744,7 +1744,7 @@ static AudioState *audio_init(Audiodev *dev, Error **errp) + if (driver) { + done = !audio_driver_init(s, driver, dev, errp); + } else { +- error_setg(errp, "Unknown audio driver `%s'\n", drvname); ++ error_setg(errp, "Unknown audio driver `%s'", drvname); + } + if (!done) { + goto out; +-- +1.8.3.1 + diff --git a/0012-hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch b/0012-hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch new file mode 100644 index 0000000000000000000000000000000000000000..da689e13751e80068e396c4e16b9adeb08af3017 --- /dev/null +++ b/0012-hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch @@ -0,0 +1,47 @@ +From 6e3cfd598cb9665689a485f1a25dff7c55023120 Mon Sep 17 00:00:00 2001 +From: Bin Meng +Date: Tue, 2 Jan 2024 22:18:03 +0800 +Subject: [PATCH 012/293] hw/net: cadence_gem: Fix MDIO_OP_xxx values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Testing upstream U-Boot with 'sifive_u' machine we see: + + => dhcp + ethernet@10090000: PHY present at 0 + Could not get PHY for ethernet@10090000: addr 0 + phy_connect failed + +This has been working till QEMU 8.1 but broken since QEMU 8.2. + +Fixes: 1b09eeb122aa ("hw/net/cadence_gem: use FIELD to describe PHYMNTNC register fields") +Reported-by: Heinrich Schuchardt +Signed-off-by: Bin Meng +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Heinrich Schuchardt +Signed-off-by: Michael Tokarev +(cherry picked from commit 0c7ffc977195c1f71c8132eb5616827e589d4a0f) +Signed-off-by: Michael Tokarev +--- + hw/net/cadence_gem.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c +index 296bba2..472ce9c 100644 +--- a/hw/net/cadence_gem.c ++++ b/hw/net/cadence_gem.c +@@ -199,8 +199,8 @@ REG32(PHYMNTNC, 0x34) /* Phy Maintenance reg */ + FIELD(PHYMNTNC, PHY_ADDR, 23, 5) + FIELD(PHYMNTNC, OP, 28, 2) + FIELD(PHYMNTNC, ST, 30, 2) +-#define MDIO_OP_READ 0x3 +-#define MDIO_OP_WRITE 0x2 ++#define MDIO_OP_READ 0x2 ++#define MDIO_OP_WRITE 0x1 + + REG32(RXPAUSE, 0x38) /* RX Pause Time reg */ + REG32(TXPAUSE, 0x3c) /* TX Pause Time reg */ +-- +1.8.3.1 + diff --git a/0013-edu-fix-DMA-range-upper-bound-check.patch b/0013-edu-fix-DMA-range-upper-bound-check.patch new file mode 100644 index 0000000000000000000000000000000000000000..c15d9ce6893707e3cd65ea570f9f40e47dec30db --- /dev/null +++ b/0013-edu-fix-DMA-range-upper-bound-check.patch @@ -0,0 +1,46 @@ +From 0bf355e6ca947b119b5d6b91a349ec607a137d94 Mon Sep 17 00:00:00 2001 +From: Max Erenberg +Date: Mon, 25 Dec 2023 18:44:32 -0500 +Subject: [PATCH 013/293] edu: fix DMA range upper bound check + +The edu_check_range function checks that start <= end1 < end2, where +end1 is the upper bound (exclusive) of the guest-supplied DMA range and +end2 is the upper bound (exclusive) of the device's allowed DMA range. +When the guest tries to transfer exactly DMA_SIZE (4096) bytes, end1 +will be equal to end2, so the check fails and QEMU aborts with this +puzzling error message (newlines added for formatting): + + qemu: hardware error: EDU: DMA range + 0x0000000000040000-0x0000000000040fff out of bounds + (0x0000000000040000-0x0000000000040fff)! + +By checking end1 <= end2 instead, guests will be allowed to transfer +exactly 4096 bytes. It is not necessary to explicitly check for +start <= end1 because the previous two checks (within(addr, start, end2) +and end1 > addr) imply start < end1. + +Fixes: b30934cb52a7 ("hw: misc, add educational driver", 2015-01-21) +Signed-off-by: Max Erenberg +Signed-off-by: Michael Tokarev +(cherry picked from commit 2c5107e1b455d4a157124f021826ead4e04b4aea) +Signed-off-by: Michael Tokarev +--- + hw/misc/edu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/misc/edu.c b/hw/misc/edu.c +index a1f8bc7..e64a246 100644 +--- a/hw/misc/edu.c ++++ b/hw/misc/edu.c +@@ -115,7 +115,7 @@ static void edu_check_range(uint64_t addr, uint64_t size1, uint64_t start, + uint64_t end2 = start + size2; + + if (within(addr, start, end2) && +- end1 > addr && within(end1, start, end2)) { ++ end1 > addr && end1 <= end2) { + return; + } + +-- +1.8.3.1 + diff --git a/0014-vfio-container-Replace-basename-with-g_path_get_base.patch b/0014-vfio-container-Replace-basename-with-g_path_get_base.patch new file mode 100644 index 0000000000000000000000000000000000000000..1a660f6cf069488e28de95c352c102fb805c23e2 --- /dev/null +++ b/0014-vfio-container-Replace-basename-with-g_path_get_base.patch @@ -0,0 +1,52 @@ +From 5f64bed67ca23976c0d00209559a35e61a6e1f96 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= +Date: Wed, 20 Dec 2023 14:53:02 +0100 +Subject: [PATCH 014/293] vfio/container: Replace basename with + g_path_get_basename +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +g_path_get_basename() is a portable utility function that has the +advantage of not modifing the string argument. It also fixes a compile +breakage with the Musl C library reported in [1]. + +[1] https://lore.kernel.org/all/20231212010228.2701544-1-raj.khem@gmail.com/ + +Reported-by: Khem Raj +Reviewed-by: Eric Auger +Reviewed-by: Zhao Liu +Reviewed-by: Zhenzhong Duan +Signed-off-by: Cédric Le Goater +(cherry picked from commit 213ae3ffda463c0503e39e0cf827511b5298c314) +Signed-off-by: Michael Tokarev +--- + hw/vfio/container.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/hw/vfio/container.c b/hw/vfio/container.c +index 2420100..adc3005 100644 +--- a/hw/vfio/container.c ++++ b/hw/vfio/container.c +@@ -848,7 +848,8 @@ static void vfio_put_base_device(VFIODevice *vbasedev) + + static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp) + { +- char *tmp, group_path[PATH_MAX], *group_name; ++ char *tmp, group_path[PATH_MAX]; ++ g_autofree char *group_name = NULL; + int ret, groupid; + ssize_t len; + +@@ -864,7 +865,7 @@ static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp) + + group_path[len] = 0; + +- group_name = basename(group_path); ++ group_name = g_path_get_basename(group_path); + if (sscanf(group_name, "%d", &groupid) != 1) { + error_setg_errno(errp, errno, "failed to read %s", group_path); + return -errno; +-- +1.8.3.1 + diff --git a/0015-hw-vfio-fix-iteration-over-global-VFIODevice-list.patch b/0015-hw-vfio-fix-iteration-over-global-VFIODevice-list.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a13fa18163f13e45e4a07000e766aed7813747f --- /dev/null +++ b/0015-hw-vfio-fix-iteration-over-global-VFIODevice-list.patch @@ -0,0 +1,66 @@ +From ae594658663b8408299d0546a8a450efb8ad5494 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Volker=20R=C3=BCmelin?= +Date: Fri, 29 Dec 2023 21:38:54 +0100 +Subject: [PATCH 015/293] hw/vfio: fix iteration over global VFIODevice list +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 3d779abafe ("vfio/common: Introduce a global VFIODevice list") +introduced a global VFIODevice list, but forgot to update the list +element field name when iterating over the new list. Change the code +to use the correct list element field. + +Fixes: 3d779abafe ("vfio/common: Introduce a global VFIODevice list") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2061 +Signed-off-by: Volker Rümelin +Reviewed-by: Zhenzhong Duan +Reviewed-by: Cédric Le Goater +Reviewed-by: Eric Auger +(cherry picked from commit 9353b6da430f90e47f352dbf6dc31120c8914da6) +Signed-off-by: Michael Tokarev +--- + hw/vfio/common.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index e70fdf5..a5dfc2d 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -73,7 +73,7 @@ bool vfio_mig_active(void) + return false; + } + +- QLIST_FOREACH(vbasedev, &vfio_device_list, next) { ++ QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { + if (vbasedev->migration_blocker) { + return false; + } +@@ -94,7 +94,7 @@ static bool vfio_multiple_devices_migration_is_supported(void) + unsigned int device_num = 0; + bool all_support_p2p = true; + +- QLIST_FOREACH(vbasedev, &vfio_device_list, next) { ++ QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { + if (vbasedev->migration) { + device_num++; + +@@ -1352,13 +1352,13 @@ void vfio_reset_handler(void *opaque) + { + VFIODevice *vbasedev; + +- QLIST_FOREACH(vbasedev, &vfio_device_list, next) { ++ QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { + if (vbasedev->dev->realized) { + vbasedev->ops->vfio_compute_needs_reset(vbasedev); + } + } + +- QLIST_FOREACH(vbasedev, &vfio_device_list, next) { ++ QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { + if (vbasedev->dev->realized && vbasedev->needs_reset) { + vbasedev->ops->vfio_hot_reset_multi(vbasedev); + } +-- +1.8.3.1 + diff --git a/0016-hw-intc-arm_gicv3_cpuif-handle-LPIs-in-in-the-list-r.patch b/0016-hw-intc-arm_gicv3_cpuif-handle-LPIs-in-in-the-list-r.patch new file mode 100644 index 0000000000000000000000000000000000000000..52da7d42bfdb39d228b1ca39c957eeb59a4acc1a --- /dev/null +++ b/0016-hw-intc-arm_gicv3_cpuif-handle-LPIs-in-in-the-list-r.patch @@ -0,0 +1,70 @@ +From a68fc9dbde1708f49021d44181000e543304d180 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Tue, 9 Jan 2024 14:43:44 +0000 +Subject: [PATCH 016/293] hw/intc/arm_gicv3_cpuif: handle LPIs in in the list + registers + +The hypervisor can deliver (virtual) LPIs to a guest by setting up a +list register to have an intid which is an LPI. The GIC has to treat +these a little differently to standard interrupt IDs, because LPIs +have no Active state, and so the guest will only EOI them, it will +not also deactivate them. So icv_eoir_write() must do two things: + + * if the LPI ID is not in any list register, we drop the + priority but do not increment the EOI count + * if the LPI ID is in a list register, we immediately deactivate + it, regardless of the split-drop-and-deactivate control + +This can be seen in the VirtualWriteEOIR0() and VirtualWriteEOIR1() +pseudocode in the GICv3 architecture specification. + +Without this fix, potentially a hypervisor guest might stall because +LPIs get stuck in a bogus Active+Pending state. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Tested-by: Miguel Luis +(cherry picked from commit 82a65e3188abebb509510b391726711606aca642) +Signed-off-by: Michael Tokarev +--- + hw/intc/arm_gicv3_cpuif.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c +index ab1a005..258dee1 100644 +--- a/hw/intc/arm_gicv3_cpuif.c ++++ b/hw/intc/arm_gicv3_cpuif.c +@@ -1434,16 +1434,25 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, + idx = icv_find_active(cs, irq); + + if (idx < 0) { +- /* No valid list register corresponding to EOI ID */ +- icv_increment_eoicount(cs); ++ /* ++ * No valid list register corresponding to EOI ID; if this is a vLPI ++ * not in the list regs then do nothing; otherwise increment EOI count ++ */ ++ if (irq < GICV3_LPI_INTID_START) { ++ icv_increment_eoicount(cs); ++ } + } else { + uint64_t lr = cs->ich_lr_el2[idx]; + int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0; + int lr_gprio = ich_lr_prio(lr) & icv_gprio_mask(cs, grp); + + if (thisgrp == grp && lr_gprio == dropprio) { +- if (!icv_eoi_split(env, cs)) { +- /* Priority drop and deactivate not split: deactivate irq now */ ++ if (!icv_eoi_split(env, cs) || irq >= GICV3_LPI_INTID_START) { ++ /* ++ * Priority drop and deactivate not split: deactivate irq now. ++ * LPIs always get their active state cleared immediately ++ * because no separate deactivate is expected. ++ */ + icv_deactivate_irq(cs, idx); + } + } +-- +1.8.3.1 + diff --git a/0017-tcg-ppc-Use-new-registers-for-LQ-destination.patch b/0017-tcg-ppc-Use-new-registers-for-LQ-destination.patch new file mode 100644 index 0000000000000000000000000000000000000000..dcddfd5f3e879991f7b81d930b4d90d62de3ac79 --- /dev/null +++ b/0017-tcg-ppc-Use-new-registers-for-LQ-destination.patch @@ -0,0 +1,151 @@ +From b88191085977d0659fab6ebdead8488e5c34c8b6 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Tue, 2 Jan 2024 01:27:18 +0000 +Subject: [PATCH 017/293] tcg/ppc: Use new registers for LQ destination +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +LQ has a constraint that RTp != RA, else SIGILL. +Therefore, force the destination of INDEX_op_qemu_*_ld128 to be a +new register pair, so that it cannot overlap the input address. + +This requires new support in process_op_defs and tcg_reg_alloc_op. + +Cc: qemu-stable@nongnu.org +Fixes: 526cd4ec01f ("tcg/ppc: Support 128-bit load/store") +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20240102013456.131846-1-richard.henderson@linaro.org> +Signed-off-by: Richard Henderson +(cherry picked from commit ca5bed07d0e7e0530c2cafbc134c4f74e582ac50) +Signed-off-by: Michael Tokarev +--- + tcg/ppc/tcg-target-con-set.h | 2 +- + tcg/ppc/tcg-target.c.inc | 3 ++- + tcg/tcg.c | 21 ++++++++++++++++----- + 3 files changed, 19 insertions(+), 7 deletions(-) + +diff --git a/tcg/ppc/tcg-target-con-set.h b/tcg/ppc/tcg-target-con-set.h +index bbd7b21..cb47b29 100644 +--- a/tcg/ppc/tcg-target-con-set.h ++++ b/tcg/ppc/tcg-target-con-set.h +@@ -35,7 +35,7 @@ C_O1_I3(v, v, v, v) + C_O1_I4(r, r, ri, rZ, rZ) + C_O1_I4(r, r, r, ri, ri) + C_O2_I1(r, r, r) +-C_O2_I1(o, m, r) ++C_N1O1_I1(o, m, r) + C_O2_I2(r, r, r, r) + C_O2_I4(r, r, rI, rZM, r, r) + C_O2_I4(r, r, r, r, rI, rZM) +diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc +index 856c3b1..5481696 100644 +--- a/tcg/ppc/tcg-target.c.inc ++++ b/tcg/ppc/tcg-target.c.inc +@@ -2595,6 +2595,7 @@ static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg datalo, TCGReg datahi, + tcg_debug_assert(!need_bswap); + tcg_debug_assert(datalo & 1); + tcg_debug_assert(datahi == datalo - 1); ++ tcg_debug_assert(!is_ld || datahi != index); + insn = is_ld ? LQ : STQ; + tcg_out32(s, insn | TAI(datahi, index, 0)); + } else { +@@ -4071,7 +4072,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) + + case INDEX_op_qemu_ld_a32_i128: + case INDEX_op_qemu_ld_a64_i128: +- return C_O2_I1(o, m, r); ++ return C_N1O1_I1(o, m, r); + case INDEX_op_qemu_st_a32_i128: + case INDEX_op_qemu_st_a64_i128: + return C_O0_I3(o, m, r); +diff --git a/tcg/tcg.c b/tcg/tcg.c +index 896a36c..e2c38f6 100644 +--- a/tcg/tcg.c ++++ b/tcg/tcg.c +@@ -653,6 +653,7 @@ static void tcg_out_movext3(TCGContext *s, const TCGMovExtend *i1, + #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4), + + #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2), ++#define C_N1O1_I1(O1, O2, I1) C_PFX3(c_n1o1_i1_, O1, O2, I1), + #define C_N2_I1(O1, O2, I1) C_PFX3(c_n2_i1_, O1, O2, I1), + + #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1), +@@ -676,6 +677,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode); + #undef C_O1_I3 + #undef C_O1_I4 + #undef C_N1_I2 ++#undef C_N1O1_I1 + #undef C_N2_I1 + #undef C_O2_I1 + #undef C_O2_I2 +@@ -696,6 +698,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode); + #define C_O1_I4(O1, I1, I2, I3, I4) { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } }, + + #define C_N1_I2(O1, I1, I2) { .args_ct_str = { "&" #O1, #I1, #I2 } }, ++#define C_N1O1_I1(O1, O2, I1) { .args_ct_str = { "&" #O1, #O2, #I1 } }, + #define C_N2_I1(O1, O2, I1) { .args_ct_str = { "&" #O1, "&" #O2, #I1 } }, + + #define C_O2_I1(O1, O2, I1) { .args_ct_str = { #O1, #O2, #I1 } }, +@@ -718,6 +721,7 @@ static const TCGTargetOpDef constraint_sets[] = { + #undef C_O1_I3 + #undef C_O1_I4 + #undef C_N1_I2 ++#undef C_N1O1_I1 + #undef C_N2_I1 + #undef C_O2_I1 + #undef C_O2_I2 +@@ -738,6 +742,7 @@ static const TCGTargetOpDef constraint_sets[] = { + #define C_O1_I4(O1, I1, I2, I3, I4) C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4) + + #define C_N1_I2(O1, I1, I2) C_PFX3(c_n1_i2_, O1, I1, I2) ++#define C_N1O1_I1(O1, O2, I1) C_PFX3(c_n1o1_i1_, O1, O2, I1) + #define C_N2_I1(O1, O2, I1) C_PFX3(c_n2_i1_, O1, O2, I1) + + #define C_O2_I1(O1, O2, I1) C_PFX3(c_o2_i1_, O1, O2, I1) +@@ -2988,6 +2993,7 @@ static void process_op_defs(TCGContext *s) + .pair = 2, + .pair_index = o, + .regs = def->args_ct[o].regs << 1, ++ .newreg = def->args_ct[o].newreg, + }; + def->args_ct[o].pair = 1; + def->args_ct[o].pair_index = i; +@@ -3004,6 +3010,7 @@ static void process_op_defs(TCGContext *s) + .pair = 1, + .pair_index = o, + .regs = def->args_ct[o].regs >> 1, ++ .newreg = def->args_ct[o].newreg, + }; + def->args_ct[o].pair = 2; + def->args_ct[o].pair_index = i; +@@ -5036,17 +5043,21 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) + break; + + case 1: /* first of pair */ +- tcg_debug_assert(!arg_ct->newreg); + if (arg_ct->oalias) { + reg = new_args[arg_ct->alias_index]; +- break; ++ } else if (arg_ct->newreg) { ++ reg = tcg_reg_alloc_pair(s, arg_ct->regs, ++ i_allocated_regs | o_allocated_regs, ++ output_pref(op, k), ++ ts->indirect_base); ++ } else { ++ reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, ++ output_pref(op, k), ++ ts->indirect_base); + } +- reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs, +- output_pref(op, k), ts->indirect_base); + break; + + case 2: /* second of pair */ +- tcg_debug_assert(!arg_ct->newreg); + if (arg_ct->oalias) { + reg = new_args[arg_ct->alias_index]; + } else { +-- +1.8.3.1 + diff --git a/0018-util-fix-build-with-musl-libc-on-ppc64le.patch b/0018-util-fix-build-with-musl-libc-on-ppc64le.patch new file mode 100644 index 0000000000000000000000000000000000000000..982022cc9842630f1c97775a92d2aabf3c3c934c --- /dev/null +++ b/0018-util-fix-build-with-musl-libc-on-ppc64le.patch @@ -0,0 +1,59 @@ +From 9ee4603a86624a5c9507a79086110daf830159a4 Mon Sep 17 00:00:00 2001 +From: Natanael Copa +Date: Tue, 19 Dec 2023 11:51:29 +0100 +Subject: [PATCH 018/293] util: fix build with musl libc on ppc64le + +Use PPC_FEATURE2_ISEL and PPC_FEATURE2_VEC_CRYPTO from linux headers +instead of the GNU specific PPC_FEATURE2_HAS_ISEL and +PPC_FEATURE2_HAS_VEC_CRYPTO. This fixes build with musl libc. + +Cc: qemu-stable@nongnu.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1861 +Signed-off-by: Natanael Copa +Fixes: 63922f467a ("tcg/ppc: Replace HAVE_ISEL macro with a variable") +Fixes: 68f340d4cd ("tcg/ppc: Enable Altivec detection") +Message-Id: <20231219105236.7059-1-ncopa@alpinelinux.org> +Signed-off-by: Richard Henderson +(cherry picked from commit 1d513e06d96697f44de4a1b85c6ff627c443e306) +Signed-off-by: Michael Tokarev +--- + util/cpuinfo-ppc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/util/cpuinfo-ppc.c b/util/cpuinfo-ppc.c +index 1ea3db0..b2d8893 100644 +--- a/util/cpuinfo-ppc.c ++++ b/util/cpuinfo-ppc.c +@@ -6,10 +6,10 @@ + #include "qemu/osdep.h" + #include "host/cpuinfo.h" + ++#include + #ifdef CONFIG_GETAUXVAL + # include + #else +-# include + # include "elf.h" + #endif + +@@ -40,7 +40,7 @@ unsigned __attribute__((constructor)) cpuinfo_init(void) + info |= CPUINFO_V2_06; + } + +- if (hwcap2 & PPC_FEATURE2_HAS_ISEL) { ++ if (hwcap2 & PPC_FEATURE2_ISEL) { + info |= CPUINFO_ISEL; + } + if (hwcap & PPC_FEATURE_HAS_ALTIVEC) { +@@ -53,7 +53,7 @@ unsigned __attribute__((constructor)) cpuinfo_init(void) + * always have both anyway, since VSX came with Power7 + * and crypto came with Power8. + */ +- if (hwcap2 & PPC_FEATURE2_HAS_VEC_CRYPTO) { ++ if (hwcap2 & PPC_FEATURE2_VEC_CRYPTO) { + info |= CPUINFO_CRYPTO; + } + } +-- +1.8.3.1 + diff --git a/0019-tests-acpi-allow-tests-data-acpi-virt-SSDT.memhp-cha.patch b/0019-tests-acpi-allow-tests-data-acpi-virt-SSDT.memhp-cha.patch new file mode 100644 index 0000000000000000000000000000000000000000..2d235ea017e3b64bc0522fdc7f21f43bafe8fad5 --- /dev/null +++ b/0019-tests-acpi-allow-tests-data-acpi-virt-SSDT.memhp-cha.patch @@ -0,0 +1,23 @@ +From 4e875df3b677c7a4acd5ce1aa06839a2adf0a8da Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 13 Dec 2023 10:30:16 +0100 +Subject: [PATCH 019/293] tests/acpi: allow tests/data/acpi/virt/SSDT.memhp + changes + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit ca8b0cc8e9176419960b844abb522a2298a794d6) +Signed-off-by: Michael Tokarev +--- + tests/qtest/bios-tables-test-allowed-diff.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index dfb8523..e569098 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1 +1,2 @@ + /* List of comma-separated changed AML files to ignore */ ++"tests/data/acpi/virt/SSDT.memhp", +-- +1.8.3.1 + diff --git a/0020-edk2-update-build-config-set-PcdUninstallMemAttrProt.patch b/0020-edk2-update-build-config-set-PcdUninstallMemAttrProt.patch new file mode 100644 index 0000000000000000000000000000000000000000..3d646711140ce6034db01f25fbf3b84e73d4d734 --- /dev/null +++ b/0020-edk2-update-build-config-set-PcdUninstallMemAttrProt.patch @@ -0,0 +1,58 @@ +From 3b1b25cdaad5cf57c476bd1ea323c086acdd5251 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 13 Dec 2023 08:57:20 +0100 +Subject: [PATCH 021/293] edk2: update build config, set + PcdUninstallMemAttrProtocol = TRUE. + +Needed to workaround buggy EFI_MEMORY_ATTRIBUTE_PROTOCOL +usage in shim.efi. + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 6f79fa5f097aa41fc96a14dfccdb0ea8d9facd6c) +Signed-off-by: Michael Tokarev +--- + roms/edk2-build.config | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/roms/edk2-build.config b/roms/edk2-build.config +index bab6a9c..0d367db 100644 +--- a/roms/edk2-build.config ++++ b/roms/edk2-build.config +@@ -22,9 +22,15 @@ SMM_REQUIRE = TRUE + [opts.armvirt.silent] + DEBUG_PRINT_ERROR_LEVEL = 0x80000000 + +-[pcds.nx.broken.grub] ++[pcds.nx.strict] ++PcdDxeNxMemoryProtectionPolicy = 0xC000000000007FD5 ++PcdUninstallMemAttrProtocol = FALSE ++ ++[pcds.nx.broken.shim.grub] + # grub.efi uses EfiLoaderData for code + PcdDxeNxMemoryProtectionPolicy = 0xC000000000007FD1 ++# shim.efi has broken MemAttr code ++PcdUninstallMemAttrProtocol = TRUE + + [pcds.workaround.202308] + PcdFirstTimeWakeUpAPsBySipi = FALSE +@@ -95,7 +101,7 @@ conf = ArmVirtPkg/ArmVirtQemu.dsc + arch = ARM + opts = common + armvirt.silent +-pcds = nx.broken.grub ++pcds = nx.broken.shim.grub + plat = ArmVirtQemu-ARM + dest = ../pc-bios + cpy1 = FV/QEMU_EFI.fd edk2-arm-code.fd +@@ -112,7 +118,7 @@ conf = ArmVirtPkg/ArmVirtQemu.dsc + arch = AARCH64 + opts = common + armvirt.silent +-pcds = nx.broken.grub ++pcds = nx.broken.shim.grub + plat = ArmVirtQemu-AARCH64 + dest = ../pc-bios + cpy1 = FV/QEMU_EFI.fd edk2-aarch64-code.fd +-- +1.8.3.1 + diff --git a/0021-tests-acpi-disallow-tests-data-acpi-virt-SSDT.memhp-.patch b/0021-tests-acpi-disallow-tests-data-acpi-virt-SSDT.memhp-.patch new file mode 100644 index 0000000000000000000000000000000000000000..4b1eb1bb68857510b4a9ce4e007d31a1a6a3ef72 --- /dev/null +++ b/0021-tests-acpi-disallow-tests-data-acpi-virt-SSDT.memhp-.patch @@ -0,0 +1,23 @@ +From 2dd8fdfe49c0178241a2292d1ea9a40f13379c47 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 13 Dec 2023 11:21:13 +0100 +Subject: [PATCH 024/293] tests/acpi: disallow tests/data/acpi/virt/SSDT.memhp + changes + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 704f7cad5105246822686f65765ab92045f71a3b) +Signed-off-by: Michael Tokarev +--- + tests/qtest/bios-tables-test-allowed-diff.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index e569098..dfb8523 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1,2 +1 @@ + /* List of comma-separated changed AML files to ignore */ +-"tests/data/acpi/virt/SSDT.memhp", +-- +1.8.3.1 + diff --git a/0022-tests-qtest-virtio-ccw-Fix-device-presence-checking.patch b/0022-tests-qtest-virtio-ccw-Fix-device-presence-checking.patch new file mode 100644 index 0000000000000000000000000000000000000000..5cae378970fb88ed7e7f564fe12eeced2f0c2318 --- /dev/null +++ b/0022-tests-qtest-virtio-ccw-Fix-device-presence-checking.patch @@ -0,0 +1,39 @@ +From 0b27f20d6a62456ae94293deb210092e6ec9949d Mon Sep 17 00:00:00 2001 +From: Samuel Tardieu +Date: Sat, 6 Jan 2024 14:01:21 +0100 +Subject: [PATCH 025/293] tests/qtest/virtio-ccw: Fix device presence checking +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +An apparent copy-paste error tests for the presence of the +virtio-rng-ccw device in order to perform tests on the virtio-scsi-ccw +device. + +Signed-off-by: Samuel Tardieu +Message-ID: <20240106130121.1244993-1-sam@rfc1149.net> +Fixes: 65331bf5d1 ("tests/qtest: Check for virtio-ccw devices before using them") +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Thomas Huth +(cherry picked from commit c98873ee4a0c2694aac976ab9affcf55da8b7e61) +Signed-off-by: Michael Tokarev +--- + tests/qtest/virtio-ccw-test.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/qtest/virtio-ccw-test.c b/tests/qtest/virtio-ccw-test.c +index f4f5858..7a5357c 100644 +--- a/tests/qtest/virtio-ccw-test.c ++++ b/tests/qtest/virtio-ccw-test.c +@@ -85,7 +85,7 @@ int main(int argc, char **argv) + if (qtest_has_device("virtio-rng-ccw")) { + qtest_add_func("/virtio/rng/nop", virtio_rng_nop); + } +- if (qtest_has_device("virtio-rng-ccw")) { ++ if (qtest_has_device("virtio-scsi-ccw")) { + qtest_add_func("/virtio/scsi/nop", virtio_scsi_nop); + qtest_add_func("/virtio/scsi/hotplug", virtio_scsi_hotplug); + } +-- +1.8.3.1 + diff --git a/0023-target-s390x-Fix-LAE-setting-a-wrong-access-register.patch b/0023-target-s390x-Fix-LAE-setting-a-wrong-access-register.patch new file mode 100644 index 0000000000000000000000000000000000000000..dde4790005b7313ff811870793a09e5dedf39c55 --- /dev/null +++ b/0023-target-s390x-Fix-LAE-setting-a-wrong-access-register.patch @@ -0,0 +1,45 @@ +From 08b37c90e6047d6167b3ec511cd47375c9ce1427 Mon Sep 17 00:00:00 2001 +From: Ilya Leoshkevich +Date: Thu, 11 Jan 2024 10:21:26 +0100 +Subject: [PATCH 026/293] target/s390x: Fix LAE setting a wrong access register + +LAE should set the access register corresponding to the first operand, +instead, it always modifies access register 1. + +Co-developed-by: Ido Plat +Cc: qemu-stable@nongnu.org +Fixes: a1c7610a6879 ("target-s390x: implement LAY and LAEY instructions") +Reviewed-by: David Hildenbrand +Signed-off-by: Ilya Leoshkevich +Message-ID: <20240111092328.929421-2-iii@linux.ibm.com> +Signed-off-by: Thomas Huth +(cherry picked from commit e358a25a97c71c39e3513d9b869cdb82052e50b8) +Signed-off-by: Michael Tokarev +--- + target/s390x/tcg/translate.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c +index 62ab2be..8df00b7 100644 +--- a/target/s390x/tcg/translate.c ++++ b/target/s390x/tcg/translate.c +@@ -3221,6 +3221,7 @@ static DisasJumpType op_mov2e(DisasContext *s, DisasOps *o) + { + int b2 = get_field(s, b2); + TCGv ar1 = tcg_temp_new_i64(); ++ int r1 = get_field(s, r1); + + o->out = o->in2; + o->in2 = NULL; +@@ -3244,7 +3245,7 @@ static DisasJumpType op_mov2e(DisasContext *s, DisasOps *o) + break; + } + +- tcg_gen_st32_i64(ar1, tcg_env, offsetof(CPUS390XState, aregs[1])); ++ tcg_gen_st32_i64(ar1, tcg_env, offsetof(CPUS390XState, aregs[r1])); + return DISAS_NEXT; + } + +-- +1.8.3.1 + diff --git a/0024-.gitlab-ci.d-buildtest.yml-Work-around-htags-bug-whe.patch b/0024-.gitlab-ci.d-buildtest.yml-Work-around-htags-bug-whe.patch new file mode 100644 index 0000000000000000000000000000000000000000..aeb6312da21b5f43483220abc3e8bd4e7746f931 --- /dev/null +++ b/0024-.gitlab-ci.d-buildtest.yml-Work-around-htags-bug-whe.patch @@ -0,0 +1,57 @@ +From 32ade2abef75c1acd61b491d96a67d8f745af88a Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Thu, 11 Jan 2024 12:55:43 +0000 +Subject: [PATCH 027/293] .gitlab-ci.d/buildtest.yml: Work around htags bug + when environment is large +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Sometimes the CI "pages" job fails with a message like this from +htags: + +$ htags -anT --tree-view=filetree -m qemu_init -t "Welcome to the QEMU sourcecode" +htags: Negative exec line limit = -371 + +This is due to a bug in hflags where if the environment is too large it +falls over: +https://lists.gnu.org/archive/html/bug-global/2024-01/msg00000.html + +This happens to us because GitLab CI puts the commit message of the +commit under test into the CI_COMMIT_MESSAGE and/or CI_COMMIT_TAG_MESSAGE +environment variables, so the job will fail if the commit happens to +have a verbose commit message. + +Work around the htags bug by unsetting these variables while running +htags. + +Cc: qemu-stable@nongnu.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2080 +Reviewed-by: Philippe Mathieu-Daudé +Message-ID: <20240111125543.1573473-1-peter.maydell@linaro.org> +Signed-off-by: Thomas Huth +(cherry picked from commit 52a21689cd829c1cc931b59b5ee5bdb10dd578c1) +Signed-off-by: Michael Tokarev +--- + .gitlab-ci.d/buildtest.yml | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml +index 9166394..0a01746 100644 +--- a/.gitlab-ci.d/buildtest.yml ++++ b/.gitlab-ci.d/buildtest.yml +@@ -647,7 +647,10 @@ pages: + - mkdir -p public + # HTML-ised source tree + - make gtags +- - htags -anT --tree-view=filetree -m qemu_init ++ # We unset variables to work around a bug in some htags versions ++ # which causes it to fail when the environment is large ++ - CI_COMMIT_MESSAGE= CI_COMMIT_TAG_MESSAGE= htags ++ -anT --tree-view=filetree -m qemu_init + -t "Welcome to the QEMU sourcecode" + - mv HTML public/src + # Project documentation +-- +1.8.3.1 + diff --git a/0025-readthodocs-fully-specify-a-build-environment.patch b/0025-readthodocs-fully-specify-a-build-environment.patch new file mode 100644 index 0000000000000000000000000000000000000000..b0720160502c21a1a800acf903cbf2f1a7ead40f --- /dev/null +++ b/0025-readthodocs-fully-specify-a-build-environment.patch @@ -0,0 +1,68 @@ +From 35623388b03c6c46598be61ef8d5f901c815ed7a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Thu, 21 Dec 2023 17:42:00 +0000 +Subject: [PATCH 028/293] readthodocs: fully specify a build environment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is now expected by rtd so I've expanded using their example as +22.04 is one of our supported platforms. I tried to work out if there +was an easy way to re-generate a requirements.txt from our +pythondeps.toml but in the end went for the easier solution. + +Cc: +Signed-off-by: Alex Bennée +Message-Id: <20231221174200.2693694-1-alex.bennee@linaro.org> +(cherry picked from commit b16a45bc5e0e329a16af8a2e020a6e7044f9afa2) +Signed-off-by: Michael Tokarev +--- + .readthedocs.yml | 19 ++++++++++++------- + docs/requirements.txt | 2 ++ + 2 files changed, 14 insertions(+), 7 deletions(-) + create mode 100644 docs/requirements.txt + +diff --git a/.readthedocs.yml b/.readthedocs.yml +index 7fb7b8d..0b26246 100644 +--- a/.readthedocs.yml ++++ b/.readthedocs.yml +@@ -5,16 +5,21 @@ + # Required + version: 2 + ++# Set the version of Python and other tools you might need ++build: ++ os: ubuntu-22.04 ++ tools: ++ python: "3.11" ++ + # Build documentation in the docs/ directory with Sphinx + sphinx: + configuration: docs/conf.py + ++# We recommend specifying your dependencies to enable reproducible builds: ++# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html ++python: ++ install: ++ - requirements: docs/requirements.txt ++ + # We want all the document formats + formats: all +- +-# For consistency, we require that QEMU's Sphinx extensions +-# run with at least the same minimum version of Python that +-# we require for other Python in our codebase (our conf.py +-# enforces this, and some code needs it.) +-python: +- version: 3.6 +diff --git a/docs/requirements.txt b/docs/requirements.txt +new file mode 100644 +index 0000000..691e521 +--- /dev/null ++++ b/docs/requirements.txt +@@ -0,0 +1,2 @@ ++sphinx==5.3.0 ++sphinx_rtd_theme==1.1.1 +-- +1.8.3.1 + diff --git a/0026-hw-hppa-machine-Allow-up-to-3840-MB-total-memory.patch b/0026-hw-hppa-machine-Allow-up-to-3840-MB-total-memory.patch new file mode 100644 index 0000000000000000000000000000000000000000..7a033ff79f06564c70d3cb5d9743f7c63c12414c --- /dev/null +++ b/0026-hw-hppa-machine-Allow-up-to-3840-MB-total-memory.patch @@ -0,0 +1,66 @@ +From de64580f07fa4901fccc349c7f51e0e9c9e2951d Mon Sep 17 00:00:00 2001 +From: Helge Deller +Date: Sun, 31 Dec 2023 09:36:58 +0100 +Subject: [PATCH 029/293] hw/hppa/machine: Allow up to 3840 MB total memory + +The physical hardware allows DIMMs of 4 MB size and above, allowing up +to 3840 MB of memory, but is restricted by setup code to 3 GB. +Increase the limit to allow up to the maximum amount of memory. + +Btw. the memory area from 0xf000.0000 to 0xffff.ffff is reserved by +the architecture for firmware and I/O memory and can not be used for +standard memory. + +An upcoming 64-bit SeaBIOS-hppa firmware will allow more than 3.75GB +on 64-bit HPPA64. In this case the ram_max for the pa20 case will change. + +Signed-off-by: Helge Deller +Noticed-by: Nelson H. F. Beebe +Fixes: b7746b1194c8 ("hw/hppa/machine: Restrict the total memory size to 3GB") +Reviewed-by: Richard Henderson +Tested-by: Bruno Haible +(cherry picked from commit 92039f61af89629f268e04255946c2a3fa0c453f) +Signed-off-by: Michael Tokarev +--- + hw/hppa/machine.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c +index c8da7c1..b119076 100644 +--- a/hw/hppa/machine.c ++++ b/hw/hppa/machine.c +@@ -276,6 +276,7 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine) + unsigned int smp_cpus = machine->smp.cpus; + TranslateFn *translate; + MemoryRegion *cpu_region; ++ uint64_t ram_max; + + /* Create CPUs. */ + for (unsigned int i = 0; i < smp_cpus; i++) { +@@ -288,8 +289,10 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine) + */ + if (hppa_is_pa20(&cpu[0]->env)) { + translate = translate_pa20; ++ ram_max = 0xf0000000; /* 3.75 GB (limited by 32-bit firmware) */ + } else { + translate = translate_pa10; ++ ram_max = 0xf0000000; /* 3.75 GB (32-bit CPU) */ + } + + for (unsigned int i = 0; i < smp_cpus; i++) { +@@ -311,9 +314,9 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine) + cpu_region); + + /* Main memory region. */ +- if (machine->ram_size > 3 * GiB) { +- error_report("RAM size is currently restricted to 3GB"); +- exit(EXIT_FAILURE); ++ if (machine->ram_size > ram_max) { ++ info_report("Max RAM size limited to %" PRIu64 " MB", ram_max / MiB); ++ machine->ram_size = ram_max; + } + memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1); + +-- +1.8.3.1 + diff --git a/0027-hw-hppa-machine-Disable-default-devices-with-nodefau.patch b/0027-hw-hppa-machine-Disable-default-devices-with-nodefau.patch new file mode 100644 index 0000000000000000000000000000000000000000..c47163992ea26313541d01a87aed50d27d79332c --- /dev/null +++ b/0027-hw-hppa-machine-Disable-default-devices-with-nodefau.patch @@ -0,0 +1,64 @@ +From 4e68f4124fd8fd5a56af6e9f4d14aa61dd7f6c44 Mon Sep 17 00:00:00 2001 +From: Helge Deller +Date: Mon, 1 Jan 2024 21:47:30 +0100 +Subject: [PATCH 030/293] hw/hppa/machine: Disable default devices with + --nodefaults option + +Recognize the qemu --nodefaults option, which will disable the +following default devices on hppa: +- lsi53c895a SCSI controller, +- artist graphics card, +- LASI 82596 NIC, +- tulip PCI NIC, +- second serial PCI card, +- USB OHCI controller. + +Adding this option is very useful to allow manual testing and +debugging of the other possible devices on the command line. + +Signed-off-by: Helge Deller +Reviewed-by: Richard Henderson +(cherry picked from commit d8a3220005d74512677b181e3a32cd94b13ddf49) +Signed-off-by: Michael Tokarev +--- + hw/hppa/machine.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c +index b119076..54ca2fd 100644 +--- a/hw/hppa/machine.c ++++ b/hw/hppa/machine.c +@@ -346,8 +346,10 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus, + SysBusDevice *s; + + /* SCSI disk setup. */ +- dev = DEVICE(pci_create_simple(pci_bus, -1, "lsi53c895a")); +- lsi53c8xx_handle_legacy_cmdline(dev); ++ if (drive_get_max_bus(IF_SCSI) >= 0) { ++ dev = DEVICE(pci_create_simple(pci_bus, -1, "lsi53c895a")); ++ lsi53c8xx_handle_legacy_cmdline(dev); ++ } + + /* Graphics setup. */ + if (machine->enable_graphics && vga_interface_type != VGA_NONE) { +@@ -360,7 +362,7 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus, + } + + /* Network setup. */ +- if (enable_lasi_lan()) { ++ if (nd_table[0].used && enable_lasi_lan()) { + lasi_82596_init(addr_space, translate(NULL, LASI_LAN_HPA), + qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA)); + } +@@ -385,7 +387,7 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus, + pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_ID], 0x1227); /* Powerbar */ + + /* create a second serial PCI card when running Astro */ +- if (!lasi_dev) { ++ if (serial_hd(1) && !lasi_dev) { + pci_dev = pci_new(-1, "pci-serial-4x"); + qdev_prop_set_chr(DEVICE(pci_dev), "chardev1", serial_hd(1)); + qdev_prop_set_chr(DEVICE(pci_dev), "chardev2", serial_hd(2)); +-- +1.8.3.1 + diff --git a/0028-hw-pci-host-astro-Add-missing-astro-elroy-registers-.patch b/0028-hw-pci-host-astro-Add-missing-astro-elroy-registers-.patch new file mode 100644 index 0000000000000000000000000000000000000000..8620273ce87fa2741b8b3efee7c67c8cdbff1d40 --- /dev/null +++ b/0028-hw-pci-host-astro-Add-missing-astro-elroy-registers-.patch @@ -0,0 +1,103 @@ +From ad70198043559850b8d42cd1c5351ca4ee6571cb Mon Sep 17 00:00:00 2001 +From: Helge Deller +Date: Wed, 3 Jan 2024 12:45:06 +0100 +Subject: [PATCH 031/293] hw/pci-host/astro: Add missing astro & elroy + registers for NetBSD + +NetBSD accesses some astro and elroy registers which aren't accessed +by Linux yet. Add emulation for those registers to allow NetBSD to +boot further. +Please note that this patch is not sufficient to completely boot up +NetBSD on the 64-bit C3700 machine yet. + +Signed-off-by: Helge Deller +Tested-by: Bruno Haible +(cherry picked from commit 3b57c15f02050227c5c73ca97fa0dfc02f154fe9) +Signed-off-by: Michael Tokarev +--- + hw/pci-host/astro.c | 26 +++++++++++++++++++++++--- + 1 file changed, 23 insertions(+), 3 deletions(-) + +diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c +index 7d68cce..cb2c8a8 100644 +--- a/hw/pci-host/astro.c ++++ b/hw/pci-host/astro.c +@@ -166,6 +166,8 @@ static MemTxResult elroy_chip_write_with_attrs(void *opaque, hwaddr addr, + trace_elroy_write(addr, size, val); + + switch ((addr >> 3) << 3) { ++ case 0x000: /* PCI_ID & PCI_COMMAND_STATUS_REG */ ++ break; + case 0x080: + put_val_in_int64(&s->arb_mask, addr, size, val); + break; +@@ -175,6 +177,9 @@ static MemTxResult elroy_chip_write_with_attrs(void *opaque, hwaddr addr, + case 0x200 ... 0x250 - 1: /* LMMIO, GMMIO, WLMMIO, WGMMIO, ... */ + put_val_in_arrary(s->mmio_base, 0x200, addr, size, val); + break; ++ case 0x300: /* ibase */ ++ case 0x308: /* imask */ ++ break; + case 0x0680: + put_val_in_int64(&s->error_config, addr, size, val); + break; +@@ -538,6 +543,9 @@ static MemTxResult astro_chip_read_with_attrs(void *opaque, hwaddr addr, + case 0x0030: /* HP-UX 10.20 and 11.11 reads it. No idea. */ + val = -1; + break; ++ case 0x0078: /* NetBSD reads 0x78 ? */ ++ val = -1; ++ break; + case 0x0300 ... 0x03d8: /* LMMIO_DIRECT0_BASE... */ + index = (addr - 0x300) / 8; + val = s->ioc_ranges[index]; +@@ -624,31 +632,43 @@ static MemTxResult astro_chip_write_with_attrs(void *opaque, hwaddr addr, + case 0x10220: + case 0x10230: /* HP-UX 11.11 reads it. No idea. */ + break; +- case 0x22108: /* IOC STATUS_CONTROL */ +- put_val_in_int64(&s->ioc_status_ctrl, addr, size, val); +- break; + case 0x20200 ... 0x20240 - 1: /* IOC Rope0_Control ... */ + put_val_in_arrary(s->ioc_rope_control, 0x20200, addr, size, val); + break; + case 0x20040: /* IOC Rope config */ ++ case 0x22040: + put_val_in_int64(&s->ioc_rope_config, addr, size, val); + break; + case 0x20300: ++ case 0x22300: + put_val_in_int64(&s->tlb_ibase, addr, size, val); + break; + case 0x20308: ++ case 0x22308: + put_val_in_int64(&s->tlb_imask, addr, size, val); + break; + case 0x20310: ++ case 0x22310: + put_val_in_int64(&s->tlb_pcom, addr, size, val); + /* TODO: flush iommu */ + break; + case 0x20318: ++ case 0x22318: + put_val_in_int64(&s->tlb_tcnfg, addr, size, val); + break; + case 0x20320: ++ case 0x22320: + put_val_in_int64(&s->tlb_pdir_base, addr, size, val); + break; ++ case 0x22000: /* func_id */ ++ break; ++ case 0x22008: /* func_class */ ++ break; ++ case 0x22050: /* rope_debug */ ++ break; ++ case 0x22108: /* IOC STATUS_CONTROL */ ++ put_val_in_int64(&s->ioc_status_ctrl, addr, size, val); ++ break; + /* + * empty placeholders for non-existent elroys, e.g. + * func_class, pci config & data +-- +1.8.3.1 + diff --git a/0029-hw-hppa-Move-software-power-button-address-back-into.patch b/0029-hw-hppa-Move-software-power-button-address-back-into.patch new file mode 100644 index 0000000000000000000000000000000000000000..c89b18c520e5437e6a2ea845b69395c722aa0d0d --- /dev/null +++ b/0029-hw-hppa-Move-software-power-button-address-back-into.patch @@ -0,0 +1,70 @@ +From 0f5fb24fd760bf0e693d32c6d5d7b22f035a771d Mon Sep 17 00:00:00 2001 +From: Helge Deller +Date: Wed, 3 Jan 2024 20:10:01 +0100 +Subject: [PATCH 033/293] hw/hppa: Move software power button address back into + PDC + +The various operating systems (e.g. Linux, NetBSD) have issues +mapping the power button when it's stored in page zero. +NetBSD even crashes, because it fails to map that page and then +accesses unmapped memory. + +Since we now have a consistent memory mapping of PDC in 32-bit +and 64-bit address space (the lower 32-bits of the address are in +sync) the power button can be moved back to PDC space. + +This patch fixes the power button on Linux, NetBSD and HP-UX. + +Signed-off-by: Helge Deller +Tested-by: Bruno Haible +Reviewed-by: Richard Henderson +(cherry picked from commit ed35afcb331a972210816435d6b1b5de17fc7d4f) +Signed-off-by: Michael Tokarev +--- + hw/hppa/machine.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c +index 54ca2fd..9e61162 100644 +--- a/hw/hppa/machine.c ++++ b/hw/hppa/machine.c +@@ -36,8 +36,8 @@ + + #define MIN_SEABIOS_HPPA_VERSION 12 /* require at least this fw version */ + +-/* Power button address at &PAGE0->pad[4] */ +-#define HPA_POWER_BUTTON (0x40 + 4 * sizeof(uint32_t)) ++#define HPA_POWER_BUTTON (FIRMWARE_END - 0x10) ++static hwaddr soft_power_reg; + + #define enable_lasi_lan() 0 + +@@ -45,7 +45,6 @@ static DeviceState *lasi_dev; + + static void hppa_powerdown_req(Notifier *n, void *opaque) + { +- hwaddr soft_power_reg = HPA_POWER_BUTTON; + uint32_t val; + + val = ldl_be_phys(&address_space_memory, soft_power_reg); +@@ -221,7 +220,7 @@ static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus, + fw_cfg_add_file(fw_cfg, "/etc/hppa/machine", + g_memdup(mc->name, len), len); + +- val = cpu_to_le64(HPA_POWER_BUTTON); ++ val = cpu_to_le64(soft_power_reg); + fw_cfg_add_file(fw_cfg, "/etc/hppa/power-button-addr", + g_memdup(&val, sizeof(val)), sizeof(val)); + +@@ -295,6 +294,8 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine) + ram_max = 0xf0000000; /* 3.75 GB (32-bit CPU) */ + } + ++ soft_power_reg = translate(NULL, HPA_POWER_BUTTON); ++ + for (unsigned int i = 0; i < smp_cpus; i++) { + g_autofree char *name = g_strdup_printf("cpu%u-io-eir", i); + +-- +1.8.3.1 + diff --git a/0030-target-hppa-Avoid-accessing-gr0-when-raising-excepti.patch b/0030-target-hppa-Avoid-accessing-gr0-when-raising-excepti.patch new file mode 100644 index 0000000000000000000000000000000000000000..1ffd3d87fa308ef6f1dda511041e46935105cddb --- /dev/null +++ b/0030-target-hppa-Avoid-accessing-gr0-when-raising-excepti.patch @@ -0,0 +1,37 @@ +From 27cdd0ce471a6d49dd898d2c619f5f13b498daff Mon Sep 17 00:00:00 2001 +From: Helge Deller +Date: Wed, 3 Jan 2024 20:35:18 +0100 +Subject: [PATCH 034/293] target/hppa: Avoid accessing %gr0 when raising + exception + +The value of unwind_breg may reference register %r0, but we need to avoid +accessing gr0 directly and use the value 0 instead. + +At runtime I've seen unwind_breg being zero with the Linux kernel when +rfi is used to jump to smp_callin(). + +Signed-off-by: Helge Deller +Reviewed-by: Richard Henderson +Tested-by: Bruno Haible +(cherry picked from commit 5915b67013eb8c3a84e3ef05e6ba4eae55ccd173) +Signed-off-by: Michael Tokarev +--- + target/hppa/mem_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c +index 4c28c58..1387f4a 100644 +--- a/target/hppa/mem_helper.c ++++ b/target/hppa/mem_helper.c +@@ -341,7 +341,7 @@ raise_exception_with_ior(CPUHPPAState *env, int excp, uintptr_t retaddr, + + cpu_restore_state(cs, retaddr); + +- b = env->gr[env->unwind_breg]; ++ b = env->unwind_breg ? env->gr[env->unwind_breg] : 0; + b >>= (env->psw & PSW_W ? 62 : 30); + env->cr[CR_IOR] |= b << 62; + +-- +1.8.3.1 + diff --git a/0031-target-hppa-Export-function-hppa_set_ior_and_isr.patch b/0031-target-hppa-Export-function-hppa_set_ior_and_isr.patch new file mode 100644 index 0000000000000000000000000000000000000000..32fc8d391a7102068e95c1ae7f28dfaa254ac624 --- /dev/null +++ b/0031-target-hppa-Export-function-hppa_set_ior_and_isr.patch @@ -0,0 +1,80 @@ +From 4b3064ec9017c065aa944dec5b956c2e7d6ce2d9 Mon Sep 17 00:00:00 2001 +From: Helge Deller +Date: Thu, 11 Jan 2024 22:50:11 +0100 +Subject: [PATCH 035/293] target/hppa: Export function hppa_set_ior_and_isr() + +Move functionality to set IOR and ISR on fault into own +function. This will be used by follow-up patches. + +Signed-off-by: Helge Deller +Reviewed-by: Richard Henderson +(cherry picked from commit 3824e0d643f34ee09e0cc75190c0c4b60928b78c) +Signed-off-by: Michael Tokarev +--- + target/hppa/cpu.h | 1 + + target/hppa/mem_helper.c | 23 ++++++++++++----------- + 2 files changed, 13 insertions(+), 11 deletions(-) + +diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h +index 8be45c6..9556e95 100644 +--- a/target/hppa/cpu.h ++++ b/target/hppa/cpu.h +@@ -385,6 +385,7 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int); + #ifndef CONFIG_USER_ONLY + void hppa_ptlbe(CPUHPPAState *env); + hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr); ++void hppa_set_ior_and_isr(CPUHPPAState *env, vaddr addr, bool mmu_disabled); + bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); +diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c +index 1387f4a..4fcc612 100644 +--- a/target/hppa/mem_helper.c ++++ b/target/hppa/mem_helper.c +@@ -305,14 +305,8 @@ hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) + return excp == EXCP_DTLB_MISS ? -1 : phys; + } + +-G_NORETURN static void +-raise_exception_with_ior(CPUHPPAState *env, int excp, uintptr_t retaddr, +- vaddr addr, bool mmu_disabled) ++void hppa_set_ior_and_isr(CPUHPPAState *env, vaddr addr, bool mmu_disabled) + { +- CPUState *cs = env_cpu(env); +- +- cs->exception_index = excp; +- + if (env->psw & PSW_Q) { + /* + * For pa1.x, the offset and space never overlap, and so we +@@ -339,16 +333,23 @@ raise_exception_with_ior(CPUHPPAState *env, int excp, uintptr_t retaddr, + */ + uint64_t b; + +- cpu_restore_state(cs, retaddr); +- + b = env->unwind_breg ? env->gr[env->unwind_breg] : 0; + b >>= (env->psw & PSW_W ? 62 : 30); + env->cr[CR_IOR] |= b << 62; +- +- cpu_loop_exit(cs); + } + } + } ++} ++ ++G_NORETURN static void ++raise_exception_with_ior(CPUHPPAState *env, int excp, uintptr_t retaddr, ++ vaddr addr, bool mmu_disabled) ++{ ++ CPUState *cs = env_cpu(env); ++ ++ cs->exception_index = excp; ++ hppa_set_ior_and_isr(env, addr, mmu_disabled); ++ + cpu_loop_exit_restore(cs, retaddr); + } + +-- +1.8.3.1 + diff --git a/0032-target-hppa-Fix-IOR-and-ISR-on-unaligned-access-trap.patch b/0032-target-hppa-Fix-IOR-and-ISR-on-unaligned-access-trap.patch new file mode 100644 index 0000000000000000000000000000000000000000..cdabbb8e2b3612a5319feac4a14dc6a7d57ab29c --- /dev/null +++ b/0032-target-hppa-Fix-IOR-and-ISR-on-unaligned-access-trap.patch @@ -0,0 +1,35 @@ +From abf489be5a1aced7b0995787874c679c26577403 Mon Sep 17 00:00:00 2001 +From: Helge Deller +Date: Thu, 11 Jan 2024 23:09:47 +0100 +Subject: [PATCH 036/293] target/hppa: Fix IOR and ISR on unaligned access trap + +Put correct values (depending on CPU arch) into IOR and ISR on fault. + +Signed-off-by: Helge Deller +Reviewed-by: Richard Henderson +(cherry picked from commit 910ada0225d17530188aa45afcb9412c17267f46) +Signed-off-by: Michael Tokarev +--- + target/hppa/cpu.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c +index 04de168..fda32d7 100644 +--- a/target/hppa/cpu.c ++++ b/target/hppa/cpu.c +@@ -110,11 +110,7 @@ void hppa_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + CPUHPPAState *env = &cpu->env; + + cs->exception_index = EXCP_UNALIGN; +- if (env->psw & PSW_Q) { +- /* ??? Needs tweaking for hppa64. */ +- env->cr[CR_IOR] = addr; +- env->cr[CR_ISR] = addr >> 32; +- } ++ hppa_set_ior_and_isr(env, addr, MMU_IDX_MMU_DISABLED(mmu_idx)); + + cpu_loop_exit_restore(cs, retaddr); + } +-- +1.8.3.1 + diff --git a/0033-target-hppa-Fix-IOR-and-ISR-on-error-in-probe.patch b/0033-target-hppa-Fix-IOR-and-ISR-on-error-in-probe.patch new file mode 100644 index 0000000000000000000000000000000000000000..874b1299912df3b7372e79019d890e95a04c1112 --- /dev/null +++ b/0033-target-hppa-Fix-IOR-and-ISR-on-error-in-probe.patch @@ -0,0 +1,35 @@ +From 067aa95c4782a5de7796bc3aa1763b38c6d16613 Mon Sep 17 00:00:00 2001 +From: Helge Deller +Date: Wed, 3 Jan 2024 19:51:13 +0100 +Subject: [PATCH 037/293] target/hppa: Fix IOR and ISR on error in probe + +Put correct values (depending on CPU arch) into IOR and ISR on fault. + +Signed-off-by: Helge Deller +Reviewed-by: Richard Henderson +(cherry picked from commit 31efbe72c6cc54b9cbc2505d78870a8a87a8d392) +Signed-off-by: Michael Tokarev +--- + target/hppa/op_helper.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c +index 7f607c3..ce15469 100644 +--- a/target/hppa/op_helper.c ++++ b/target/hppa/op_helper.c +@@ -351,11 +351,7 @@ target_ulong HELPER(probe)(CPUHPPAState *env, target_ulong addr, + excp = hppa_get_physical_address(env, addr, mmu_idx, 0, &phys, + &prot, NULL); + if (excp >= 0) { +- if (env->psw & PSW_Q) { +- /* ??? Needs tweaking for hppa64. */ +- env->cr[CR_IOR] = addr; +- env->cr[CR_ISR] = addr >> 32; +- } ++ hppa_set_ior_and_isr(env, addr, MMU_IDX_MMU_DISABLED(mmu_idx)); + if (excp == EXCP_DTLB_MISS) { + excp = EXCP_NA_DTLB_MISS; + } +-- +1.8.3.1 + diff --git a/0033-target-loongarch-kvm-Add-pmu-support.patch b/0033-target-loongarch-kvm-Add-pmu-support.patch deleted file mode 100644 index b4881f8d272f43c72d25c9c65eeaae94d98470fb..0000000000000000000000000000000000000000 --- a/0033-target-loongarch-kvm-Add-pmu-support.patch +++ /dev/null @@ -1,224 +0,0 @@ -From 9e21ba794167d715590bb05f373b09b6409da8cc Mon Sep 17 00:00:00 2001 -From: Song Gao -Date: Fri, 22 Mar 2024 19:26:35 +0800 -Subject: [PATCH] target/loongarch/kvm: Add pmu support - -This patch adds PMU support - e.g - '... -cpu max,pmu=on,pmnum=[1-16]'; - '... -cpu max,pmu=on' (default pmnum = 4); - '... -cpu max,pmu=off' (disable PMU) - -Signed-off-by: Song Gao ---- - target/loongarch/cpu.c | 64 +++++++++++++++++++++++++++ - target/loongarch/cpu.h | 2 + - target/loongarch/kvm/kvm.c | 55 ++++++++++++++++++++++- - target/loongarch/loongarch-qmp-cmds.c | 2 +- - 4 files changed, 121 insertions(+), 2 deletions(-) - -diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c -index b098b1c6f3..86d18f89a4 100644 ---- a/target/loongarch/cpu.c -+++ b/target/loongarch/cpu.c -@@ -8,6 +8,7 @@ - #include "qemu/osdep.h" - #include "qemu/log.h" - #include "qemu/qemu-print.h" -+#include "qemu/error-report.h" - #include "qapi/error.h" - #include "qemu/module.h" - #include "sysemu/qtest.h" -@@ -19,6 +20,7 @@ - #include "internals.h" - #include "fpu/softfloat-helpers.h" - #include "cpu-csr.h" -+#include "qapi/visitor.h" - #include "sysemu/reset.h" - #include "vec.h" - #ifdef CONFIG_KVM -@@ -420,6 +422,14 @@ static void loongarch_la464_initfn(Object *obj) - data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1); - env->cpucfg[5] = data; - -+ if (kvm_enabled()) { -+ data = 0; -+ data = FIELD_DP32(data, CPUCFG6, PMP, 1); -+ data = FIELD_DP32(data, CPUCFG6, PMNUM, 3); -+ data = FIELD_DP32(data, CPUCFG6, PMBITS, 63); -+ env->cpucfg[6] = data; -+ } -+ - data = 0; - data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1); - data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1); -@@ -654,6 +664,48 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp) - } - } - -+static bool loongarch_get_pmu(Object *obj, Error **errp) -+{ -+ LoongArchCPU *cpu = LOONGARCH_CPU(obj); -+ -+ return !!(FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP)); -+} -+ -+static void loongarch_set_pmu(Object *obj, bool value, Error **errp) -+{ -+ LoongArchCPU *cpu = LOONGARCH_CPU(obj); -+ -+ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, value); -+} -+ -+static void loongarch_get_pmnum(Object *obj, Visitor *v, -+ const char *name, void *opaque, -+ Error **errp) -+{ -+ LoongArchCPU *cpu = LOONGARCH_CPU(obj); -+ uint32_t value = FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMNUM); -+ -+ visit_type_uint32(v, name, &value, errp); -+} -+ -+static void loongarch_set_pmnum(Object *obj, Visitor *v, -+ const char *name, void *opaque, -+ Error **errp) -+{ -+ LoongArchCPU *cpu = LOONGARCH_CPU(obj); -+ uint32_t *value= opaque; -+ -+ if (!visit_type_uint32(v, name, value, errp)) { -+ return; -+ } -+ if ((*value <= PMNUM_MAX) && (*value > 0)) { -+ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMNUM, *value -1); -+ } else { -+ error_report("Performance counter number need be in [1- %d]\n", PMNUM_MAX); -+ exit(EXIT_FAILURE); -+ } -+} -+ - void loongarch_cpu_post_init(Object *obj) - { - LoongArchCPU *cpu = LOONGARCH_CPU(obj); -@@ -666,6 +718,18 @@ void loongarch_cpu_post_init(Object *obj) - object_property_add_bool(obj, "lasx", loongarch_get_lasx, - loongarch_set_lasx); - } -+ -+ if (kvm_enabled()) { -+ object_property_add_bool(obj, "pmu", loongarch_get_pmu, -+ loongarch_set_pmu); -+ if (FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP)) { -+ uint32_t value = 4; -+ object_property_add(obj, "pmnum", "uint32", -+ loongarch_get_pmnum, -+ loongarch_set_pmnum, NULL, -+ (void *)&value); -+ } -+ } - } - - static void loongarch_cpu_init(Object *obj) -diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h -index 4749d41c8c..80cad24fa1 100644 ---- a/target/loongarch/cpu.h -+++ b/target/loongarch/cpu.h -@@ -186,6 +186,8 @@ FIELD(CPUCFG6, PMNUM, 4, 4) - FIELD(CPUCFG6, PMBITS, 8, 6) - FIELD(CPUCFG6, UPM, 14, 1) - -+#define PMNUM_MAX 16 -+ - /* cpucfg[16] bits */ - FIELD(CPUCFG16, L1_IUPRE, 0, 1) - FIELD(CPUCFG16, L1_IUUNIFY, 1, 1) -diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index 49d02076ad..5dda631b2b 100644 ---- a/target/loongarch/kvm/kvm.c -+++ b/target/loongarch/kvm/kvm.c -@@ -573,6 +573,53 @@ static int kvm_check_cpucfg2(CPUState *cs) - return ret; - } - -+static int kvm_check_cpucfg6(CPUState *cs) -+{ -+ int ret; -+ uint64_t val; -+ struct kvm_device_attr attr = { -+ .group = KVM_LOONGARCH_VCPU_CPUCFG, -+ .attr = 6, -+ .addr = (uint64_t)&val, -+ }; -+ LoongArchCPU *cpu = LOONGARCH_CPU(cs); -+ CPULoongArchState *env = &cpu->env; -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr); -+ if (!ret) { -+ kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr); -+ -+ if (FIELD_EX32(env->cpucfg[6], CPUCFG6, PMP)) { -+ /* Check PMP */ -+ if (!FIELD_EX32(val, CPUCFG6, PMP)) { -+ error_report("'pmu' feature not supported by KVM on this host" -+ " Please disable 'pmu' with " -+ "'... -cpu XXX,pmu=off ...'\n"); -+ exit(EXIT_FAILURE); -+ } -+ /* Check PMNUM */ -+ int guest_pmnum = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMNUM); -+ int host_pmnum = FIELD_EX32(val, CPUCFG6, PMNUM); -+ if (guest_pmnum > host_pmnum){ -+ warn_report("The guest pmnum %d larger than KVM support %d\n", -+ guest_pmnum, host_pmnum); -+ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, -+ PMNUM, host_pmnum); -+ } -+ /* Check PMBITS */ -+ int guest_pmbits = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMBITS); -+ int host_pmbits = FIELD_EX32(val, CPUCFG6, PMBITS); -+ if (guest_pmbits != host_pmbits) { -+ warn_report("The host not support PMBITS %d\n", guest_pmbits); -+ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, -+ PMBITS, host_pmbits); -+ } -+ } -+ } -+ -+ return ret; -+} -+ - static int kvm_loongarch_put_cpucfg(CPUState *cs) - { - int i, ret = 0; -@@ -586,7 +633,13 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs) - if (ret) { - return ret; - } -- } -+ } -+ if (i == 6) { -+ ret = kvm_check_cpucfg6(cs); -+ if (ret) { -+ return ret; -+ } -+ } - val = env->cpucfg[i]; - ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val); - if (ret < 0) { -diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c -index 645672ff59..2612f43de9 100644 ---- a/target/loongarch/loongarch-qmp-cmds.c -+++ b/target/loongarch/loongarch-qmp-cmds.c -@@ -42,7 +42,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) - } - - static const char *cpu_model_advertised_features[] = { -- "lsx", "lasx", NULL -+ "lsx", "lasx", "pmu", "pmnum", NULL - }; - - CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, --- -2.33.0 - diff --git a/0034-load_elf-fix-iterator-s-type-for-elf-file-processing.patch b/0034-load_elf-fix-iterator-s-type-for-elf-file-processing.patch new file mode 100644 index 0000000000000000000000000000000000000000..ebc555c6a7e3cb7b33a4745c29c784b8c2eadca4 --- /dev/null +++ b/0034-load_elf-fix-iterator-s-type-for-elf-file-processing.patch @@ -0,0 +1,42 @@ +From 72dd722370864fbd4bedb218a8df6b71867c47e1 Mon Sep 17 00:00:00 2001 +From: Anastasia Belova +Date: Mon, 15 Jan 2024 12:22:16 +0300 +Subject: [PATCH 039/293] load_elf: fix iterator's type for elf file processing + +j is used while loading an ELF file to byteswap segments' +data. If data is larger than 2GB an overflow may happen. +So j should be elf_word. + +This commit fixes a minor bug: it's unlikely anybody is trying to +load ELF files with 2GB+ segments for wrong-endianness targets, +but if they did, it wouldn't work correctly. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Cc: qemu-stable@nongnu.org +Fixes: 7ef295ea5b ("loader: Add data swap option to load-elf") +Signed-off-by: Anastasia Belova +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +(cherry picked from commit 410c2a4d75f52f6a2fe978eda5a9b6f854afe5ea) +Signed-off-by: Michael Tokarev +--- + include/hw/elf_ops.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h +index 0a5c258..9c35d1b 100644 +--- a/include/hw/elf_ops.h ++++ b/include/hw/elf_ops.h +@@ -500,7 +500,7 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd, + } + + if (data_swab) { +- int j; ++ elf_word j; + for (j = 0; j < file_size; j += (1 << data_swab)) { + uint8_t *dp = data + j; + switch (data_swab) { +-- +1.8.3.1 + diff --git a/0035-target-i386-Do-not-re-compute-new-pc-with-CF_PCREL.patch b/0035-target-i386-Do-not-re-compute-new-pc-with-CF_PCREL.patch new file mode 100644 index 0000000000000000000000000000000000000000..dbff40ad1c4b5f5241703aa71388d8ff82f1439d --- /dev/null +++ b/0035-target-i386-Do-not-re-compute-new-pc-with-CF_PCREL.patch @@ -0,0 +1,53 @@ +From 6e8e580e3947eb77d1757a6ea59c58bd311bcb7e Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Tue, 2 Jan 2024 10:06:17 +1100 +Subject: [PATCH 040/293] target/i386: Do not re-compute new pc with CF_PCREL + +With PCREL, we have a page-relative view of EIP, and an +approximation of PC = EIP+CSBASE that is good enough to +detect page crossings. If we try to recompute PC after +masking EIP, we will mess up that approximation and write +a corrupt value to EIP. + +We already handled masking properly for PCREL, so the +fix in b5e0d5d2 was only needed for the !PCREL path. + +Cc: qemu-stable@nongnu.org +Fixes: b5e0d5d22fbf ("target/i386: Fix 32-bit wrapping of pc/eip computation") +Reported-by: Michael Tokarev +Signed-off-by: Richard Henderson +Message-ID: <20240101230617.129349-1-richard.henderson@linaro.org> +Signed-off-by: Paolo Bonzini +(cherry picked from commit a58506b748b8988a95f4fa1a2420ac5c17038b30) +Signed-off-by: Michael Tokarev +--- + target/i386/tcg/translate.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c +index 037bc47..e68375b 100644 +--- a/target/i386/tcg/translate.c ++++ b/target/i386/tcg/translate.c +@@ -2845,10 +2845,6 @@ static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num) + } + } + new_eip &= mask; +- new_pc = new_eip + s->cs_base; +- if (!CODE64(s)) { +- new_pc = (uint32_t)new_pc; +- } + + gen_update_cc_op(s); + set_cc_op(s, CC_OP_DYNAMIC); +@@ -2864,6 +2860,8 @@ static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num) + tcg_gen_andi_tl(cpu_eip, cpu_eip, mask); + use_goto_tb = false; + } ++ } else if (!CODE64(s)) { ++ new_pc = (uint32_t)(new_eip + s->cs_base); + } + + if (use_goto_tb && translator_use_goto_tb(&s->base, new_pc)) { +-- +1.8.3.1 + diff --git a/0036-target-i386-fix-incorrect-EIP-in-PC-relative-transla.patch b/0036-target-i386-fix-incorrect-EIP-in-PC-relative-transla.patch new file mode 100644 index 0000000000000000000000000000000000000000..47995be238b2f53a86582a6c215ce3f08a308e43 --- /dev/null +++ b/0036-target-i386-fix-incorrect-EIP-in-PC-relative-transla.patch @@ -0,0 +1,40 @@ +From 652c34cbb20bccf8d1b00863c6e3da66da299cb9 Mon Sep 17 00:00:00 2001 +From: guoguangyao +Date: Mon, 15 Jan 2024 10:08:04 +0800 +Subject: [PATCH 041/293] target/i386: fix incorrect EIP in PC-relative + translation blocks + +The PCREL patches introduced a bug when updating EIP in the !CF_PCREL case. +Using s->pc in func gen_update_eip_next() solves the problem. + +Cc: qemu-stable@nongnu.org +Fixes: b5e0d5d22fbf ("target/i386: Fix 32-bit wrapping of pc/eip computation") +Signed-off-by: guoguangyao +Reviewed-by: Richard Henderson +Message-ID: <20240115020804.30272-1-guoguangyao18@mails.ucas.ac.cn> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 2926eab8969908bc068629e973062a0fb6ff3759) +Signed-off-by: Michael Tokarev +--- + target/i386/tcg/translate.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c +index e68375b..312ca0d 100644 +--- a/target/i386/tcg/translate.c ++++ b/target/i386/tcg/translate.c +@@ -566,9 +566,9 @@ static void gen_update_eip_next(DisasContext *s) + if (tb_cflags(s->base.tb) & CF_PCREL) { + tcg_gen_addi_tl(cpu_eip, cpu_eip, s->pc - s->pc_save); + } else if (CODE64(s)) { +- tcg_gen_movi_tl(cpu_eip, s->base.pc_next); ++ tcg_gen_movi_tl(cpu_eip, s->pc); + } else { +- tcg_gen_movi_tl(cpu_eip, (uint32_t)(s->base.pc_next - s->cs_base)); ++ tcg_gen_movi_tl(cpu_eip, (uint32_t)(s->pc - s->cs_base)); + } + s->pc_save = s->pc; + } +-- +1.8.3.1 + diff --git a/0037-target-i386-pcrel-store-low-bits-of-physical-address.patch b/0037-target-i386-pcrel-store-low-bits-of-physical-address.patch new file mode 100644 index 0000000000000000000000000000000000000000..fcfcbbe1d59dcb9ce82776bcef35ba5ce2355483 --- /dev/null +++ b/0037-target-i386-pcrel-store-low-bits-of-physical-address.patch @@ -0,0 +1,105 @@ +From c46f68bd7d48591c8d1cabc3b9f54c690e9c7270 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 17 Jan 2024 16:27:42 +0100 +Subject: [PATCH 042/293] target/i386: pcrel: store low bits of physical + address in data[0] + +For PC-relative translation blocks, env->eip changes during the +execution of a translation block, Therefore, QEMU must be able to +recover an instruction's PC just from the TranslationBlock struct and +the instruction data with. Because a TB will not span two pages, QEMU +stores all the low bits of EIP in the instruction data and replaces them +in x86_restore_state_to_opc. Bits 12 and higher (which may vary between +executions of a PCREL TB, since these only use the physical address in +the hash key) are kept unmodified from env->eip. The assumption is that +these bits of EIP, unlike bits 0-11, will not change as the translation +block executes. + +Unfortunately, this is incorrect when the CS base is not aligned to a page. +Then the linear address of the instructions (i.e. the one with the +CS base addred) indeed will never span two pages, but bits 12+ of EIP +can actually change. For example, if CS base is 0x80262200 and EIP = +0x6FF4, the first instruction in the translation block will be at linear +address 0x802691F4. Even a very small TB will cross to EIP = 0x7xxx, +while the linear addresses will remain comfortably within a single page. + +The fix is simply to use the low bits of the linear address for data[0], +since those don't change. Then x86_restore_state_to_opc uses tb->cs_base +to compute a temporary linear address (referring to some unknown +instruction in the TB, but with the correct values of bits 12 and higher); +the low bits are replaced with data[0], and EIP is obtained by subtracting +again the CS base. + +Huge thanks to Mark Cave-Ayland for the image and initial debugging, +and to Gitlab user @kjliew for help with bisecting another occurrence +of (hopefully!) the same bug. + +It should be relatively easy to write a testcase that performs MMIO on +an EIP with different bits 12+ than the first instruction of the translation +block; any help is welcome. + +Fixes: e3a79e0e878 ("target/i386: Enable TARGET_TB_PCREL", 2022-10-11) +Cc: qemu-stable@nongnu.org +Cc: Mark Cave-Ayland +Cc: Richard Henderson +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1759 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1964 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2012 +Signed-off-by: Paolo Bonzini +(cherry picked from commit 729ba8e933f8af5800c3a92b37e630e9bdaa9f1e) +Signed-off-by: Michael Tokarev +--- + target/i386/tcg/tcg-cpu.c | 20 ++++++++++++++++---- + target/i386/tcg/translate.c | 1 - + 2 files changed, 16 insertions(+), 5 deletions(-) + +diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c +index 6e881e9..1d54164 100644 +--- a/target/i386/tcg/tcg-cpu.c ++++ b/target/i386/tcg/tcg-cpu.c +@@ -68,14 +68,26 @@ static void x86_restore_state_to_opc(CPUState *cs, + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + int cc_op = data[1]; ++ uint64_t new_pc; + + if (tb_cflags(tb) & CF_PCREL) { +- env->eip = (env->eip & TARGET_PAGE_MASK) | data[0]; +- } else if (tb->flags & HF_CS64_MASK) { +- env->eip = data[0]; ++ /* ++ * data[0] in PC-relative TBs is also a linear address, i.e. an address with ++ * the CS base added, because it is not guaranteed that EIP bits 12 and higher ++ * stay the same across the translation block. Add the CS base back before ++ * replacing the low bits, and subtract it below just like for !CF_PCREL. ++ */ ++ uint64_t pc = env->eip + tb->cs_base; ++ new_pc = (pc & TARGET_PAGE_MASK) | data[0]; + } else { +- env->eip = (uint32_t)(data[0] - tb->cs_base); ++ new_pc = data[0]; + } ++ if (tb->flags & HF_CS64_MASK) { ++ env->eip = new_pc; ++ } else { ++ env->eip = (uint32_t)(new_pc - tb->cs_base); ++ } ++ + if (cc_op != CC_OP_DYNAMIC) { + env->cc_op = cc_op; + } +diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c +index 312ca0d..8fd49ff 100644 +--- a/target/i386/tcg/translate.c ++++ b/target/i386/tcg/translate.c +@@ -6972,7 +6972,6 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) + + dc->prev_insn_end = tcg_last_op(); + if (tb_cflags(dcbase->tb) & CF_PCREL) { +- pc_arg -= dc->cs_base; + pc_arg &= ~TARGET_PAGE_MASK; + } + tcg_gen_insn_start(pc_arg, dc->cc_op); +-- +1.8.3.1 + diff --git a/0038-backends-cryptodev-Do-not-ignore-throttle-backends-E.patch b/0038-backends-cryptodev-Do-not-ignore-throttle-backends-E.patch new file mode 100644 index 0000000000000000000000000000000000000000..6b9e2ff645dafa184874cb3fe00aa3a25bfdce70 --- /dev/null +++ b/0038-backends-cryptodev-Do-not-ignore-throttle-backends-E.patch @@ -0,0 +1,65 @@ +From a4daea6f9f187ab0340cd04a00fa2c4a82b68c34 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 20 Nov 2023 15:54:16 +0100 +Subject: [PATCH 043/293] backends/cryptodev: Do not ignore throttle/backends + Errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Both cryptodev_backend_set_throttle() and CryptoDevBackendClass::init() +can set their Error** argument. Do not ignore them, return early +on failure. Without that, running into another failure trips +error_setv()'s assertion. Use the ERRP_GUARD() macro as suggested +in commit ae7c80a7bd ("error: New macro ERRP_GUARD()"). + +Cc: qemu-stable@nongnu.org +Fixes: e7a775fd9f ("cryptodev: Account statistics") +Fixes: 2580b452ff ("cryptodev: support QoS") +Reviewed-by: zhenwei pi +Reviewed-by: Gonglei +Reviewed-by: Markus Armbruster +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20231120150418.93443-1-philmd@linaro.org> +(cherry picked from commit 484aecf2d3a75251b63481be2a0c3aef635002af) +Signed-off-by: Michael Tokarev +--- + backends/cryptodev.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/backends/cryptodev.c b/backends/cryptodev.c +index e5006bd..fff89fd 100644 +--- a/backends/cryptodev.c ++++ b/backends/cryptodev.c +@@ -398,6 +398,7 @@ static void cryptodev_backend_set_ops(Object *obj, Visitor *v, + static void + cryptodev_backend_complete(UserCreatable *uc, Error **errp) + { ++ ERRP_GUARD(); + CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc); + CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc); + uint32_t services; +@@ -406,11 +407,20 @@ cryptodev_backend_complete(UserCreatable *uc, Error **errp) + QTAILQ_INIT(&backend->opinfos); + value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg; + cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp); ++ if (*errp) { ++ return; ++ } + value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg; + cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp); ++ if (*errp) { ++ return; ++ } + + if (bc->init) { + bc->init(backend, errp); ++ if (*errp) { ++ return; ++ } + } + + services = backend->conf.crypto_services; +-- +1.8.3.1 + diff --git a/0039-hw-pflash-refactor-pflash_data_write.patch b/0039-hw-pflash-refactor-pflash_data_write.patch new file mode 100644 index 0000000000000000000000000000000000000000..3de82bfd92fe17bd6f303e757b96aa99acafa275 --- /dev/null +++ b/0039-hw-pflash-refactor-pflash_data_write.patch @@ -0,0 +1,80 @@ +From 731783ff1e7fced41dc857a0e39deadaf8ae2477 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 8 Jan 2024 17:08:57 +0100 +Subject: [PATCH 044/293] hw/pflash: refactor pflash_data_write() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Move the offset calculation, do it once at the start of the function and +let the 'p' variable point directly to the memory location which should +be updated. This makes it simpler to update other buffers than +pfl->storage in an upcoming patch. No functional change. + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Philippe Mathieu-Daudé +Message-ID: <20240108160900.104835-2-kraxel@redhat.com> +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit 3b14a555fdb627ac091559ef5931c887d06590d8) +Signed-off-by: Michael Tokarev +--- + hw/block/pflash_cfi01.c | 30 ++++++++++++++++-------------- + 1 file changed, 16 insertions(+), 14 deletions(-) + +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index 62056b1..82f592d 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -403,33 +403,35 @@ static void pflash_update(PFlashCFI01 *pfl, int offset, + static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset, + uint32_t value, int width, int be) + { +- uint8_t *p = pfl->storage; ++ uint8_t *p; + + trace_pflash_data_write(pfl->name, offset, width, value, pfl->counter); ++ p = pfl->storage + offset; ++ + switch (width) { + case 1: +- p[offset] = value; ++ p[0] = value; + break; + case 2: + if (be) { +- p[offset] = value >> 8; +- p[offset + 1] = value; ++ p[0] = value >> 8; ++ p[1] = value; + } else { +- p[offset] = value; +- p[offset + 1] = value >> 8; ++ p[0] = value; ++ p[1] = value >> 8; + } + break; + case 4: + if (be) { +- p[offset] = value >> 24; +- p[offset + 1] = value >> 16; +- p[offset + 2] = value >> 8; +- p[offset + 3] = value; ++ p[0] = value >> 24; ++ p[1] = value >> 16; ++ p[2] = value >> 8; ++ p[3] = value; + } else { +- p[offset] = value; +- p[offset + 1] = value >> 8; +- p[offset + 2] = value >> 16; +- p[offset + 3] = value >> 24; ++ p[0] = value; ++ p[1] = value >> 8; ++ p[2] = value >> 16; ++ p[3] = value >> 24; + } + break; + } +-- +1.8.3.1 + diff --git a/0040-hw-pflash-use-ldn_-be-le-_p-and-stn_-be-le-_p.patch b/0040-hw-pflash-use-ldn_-be-le-_p-and-stn_-be-le-_p.patch new file mode 100644 index 0000000000000000000000000000000000000000..522afb712e1e804bf4563e48f4584c90ff4b4f85 --- /dev/null +++ b/0040-hw-pflash-use-ldn_-be-le-_p-and-stn_-be-le-_p.patch @@ -0,0 +1,107 @@ +From 143d230d51a8f125804cb75a9bbc430e91027f61 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 8 Jan 2024 17:08:58 +0100 +Subject: [PATCH 045/293] hw/pflash: use ldn_{be,le}_p and stn_{be,le}_p +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use the helper functions we have to read/write multi-byte values +in correct byte order. + +Suggested-by: Philippe Mathieu-Daudé +Signed-off-by: Gerd Hoffmann +Reviewed-by: Philippe Mathieu-Daudé +Message-ID: <20240108160900.104835-3-kraxel@redhat.com> +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit 5dd58358a57048e5ceabf5c91c0544f4f56afdcd) +Signed-off-by: Michael Tokarev +--- + hw/block/pflash_cfi01.c | 63 +++++++------------------------------------------ + 1 file changed, 8 insertions(+), 55 deletions(-) + +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index 82f592d..f1a9dd5 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -225,34 +225,10 @@ static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset, + uint32_t ret; + + p = pfl->storage; +- switch (width) { +- case 1: +- ret = p[offset]; +- break; +- case 2: +- if (be) { +- ret = p[offset] << 8; +- ret |= p[offset + 1]; +- } else { +- ret = p[offset]; +- ret |= p[offset + 1] << 8; +- } +- break; +- case 4: +- if (be) { +- ret = p[offset] << 24; +- ret |= p[offset + 1] << 16; +- ret |= p[offset + 2] << 8; +- ret |= p[offset + 3]; +- } else { +- ret = p[offset]; +- ret |= p[offset + 1] << 8; +- ret |= p[offset + 2] << 16; +- ret |= p[offset + 3] << 24; +- } +- break; +- default: +- abort(); ++ if (be) { ++ ret = ldn_be_p(p + offset, width); ++ } else { ++ ret = ldn_le_p(p + offset, width); + } + trace_pflash_data_read(pfl->name, offset, width, ret); + return ret; +@@ -408,34 +384,11 @@ static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset, + trace_pflash_data_write(pfl->name, offset, width, value, pfl->counter); + p = pfl->storage + offset; + +- switch (width) { +- case 1: +- p[0] = value; +- break; +- case 2: +- if (be) { +- p[0] = value >> 8; +- p[1] = value; +- } else { +- p[0] = value; +- p[1] = value >> 8; +- } +- break; +- case 4: +- if (be) { +- p[0] = value >> 24; +- p[1] = value >> 16; +- p[2] = value >> 8; +- p[3] = value; +- } else { +- p[0] = value; +- p[1] = value >> 8; +- p[2] = value >> 16; +- p[3] = value >> 24; +- } +- break; ++ if (be) { ++ stn_be_p(p, width, value); ++ } else { ++ stn_le_p(p, width, value); + } +- + } + + static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, +-- +1.8.3.1 + diff --git a/0041-hw-pflash-implement-update-buffer-for-block-writes.patch b/0041-hw-pflash-implement-update-buffer-for-block-writes.patch new file mode 100644 index 0000000000000000000000000000000000000000..61fcc20e80e7e6b5b28d2508007a908c83b1eb32 --- /dev/null +++ b/0041-hw-pflash-implement-update-buffer-for-block-writes.patch @@ -0,0 +1,271 @@ +From 1fc277a0e8ccb86a29c0b6ef656d90a62ef762d9 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 8 Jan 2024 17:08:59 +0100 +Subject: [PATCH 046/293] hw/pflash: implement update buffer for block writes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add an update buffer where all block updates are staged. +Flush or discard updates properly, so we should never see +half-completed block writes in pflash storage. + +Drop a bunch of FIXME comments ;) + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Philippe Mathieu-Daudé +Message-ID: <20240108160900.104835-4-kraxel@redhat.com> +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit 284a7ee2e290e0c9b8cd3ea6164d92386933054f) +Signed-off-by: Michael Tokarev +(Mjt: drop const in hw/block/pflash_cfi01.c for before + v8.2.0-220-g7d5dc0a367 "hw/block: Constify VMState") +--- + hw/block/pflash_cfi01.c | 110 ++++++++++++++++++++++++++++++++++++------------ + hw/block/pflash_cfi02.c | 2 +- + hw/block/trace-events | 7 ++- + 3 files changed, 89 insertions(+), 30 deletions(-) + +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index f1a9dd5..5e848a9 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -80,16 +80,39 @@ struct PFlashCFI01 { + uint16_t ident3; + uint8_t cfi_table[0x52]; + uint64_t counter; +- unsigned int writeblock_size; ++ uint32_t writeblock_size; + MemoryRegion mem; + char *name; + void *storage; + VMChangeStateEntry *vmstate; + bool old_multiple_chip_handling; ++ ++ /* block update buffer */ ++ unsigned char *blk_bytes; ++ uint32_t blk_offset; + }; + + static int pflash_post_load(void *opaque, int version_id); + ++static bool pflash_blk_write_state_needed(void *opaque) ++{ ++ PFlashCFI01 *pfl = opaque; ++ ++ return (pfl->blk_offset != -1); ++} ++ ++static const VMStateDescription vmstate_pflash_blk_write = { ++ .name = "pflash_cfi01_blk_write", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .needed = pflash_blk_write_state_needed, ++ .fields = (const VMStateField[]) { ++ VMSTATE_VBUFFER_UINT32(blk_bytes, PFlashCFI01, 0, NULL, writeblock_size), ++ VMSTATE_UINT32(blk_offset, PFlashCFI01), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + static const VMStateDescription vmstate_pflash = { + .name = "pflash_cfi01", + .version_id = 1, +@@ -101,6 +124,10 @@ static const VMStateDescription vmstate_pflash = { + VMSTATE_UINT8(status, PFlashCFI01), + VMSTATE_UINT64(counter, PFlashCFI01), + VMSTATE_END_OF_LIST() ++ }, ++ .subsections = (const VMStateDescription * []) { ++ &vmstate_pflash_blk_write, ++ NULL + } + }; + +@@ -376,13 +403,55 @@ static void pflash_update(PFlashCFI01 *pfl, int offset, + } + } + ++/* copy current flash content to block update buffer */ ++static void pflash_blk_write_start(PFlashCFI01 *pfl, hwaddr offset) ++{ ++ hwaddr mask = ~(pfl->writeblock_size - 1); ++ ++ trace_pflash_write_block_start(pfl->name, pfl->counter); ++ pfl->blk_offset = offset & mask; ++ memcpy(pfl->blk_bytes, pfl->storage + pfl->blk_offset, ++ pfl->writeblock_size); ++} ++ ++/* commit block update buffer changes */ ++static void pflash_blk_write_flush(PFlashCFI01 *pfl) ++{ ++ g_assert(pfl->blk_offset != -1); ++ trace_pflash_write_block_flush(pfl->name); ++ memcpy(pfl->storage + pfl->blk_offset, pfl->blk_bytes, ++ pfl->writeblock_size); ++ pflash_update(pfl, pfl->blk_offset, pfl->writeblock_size); ++ pfl->blk_offset = -1; ++} ++ ++/* discard block update buffer changes */ ++static void pflash_blk_write_abort(PFlashCFI01 *pfl) ++{ ++ trace_pflash_write_block_abort(pfl->name); ++ pfl->blk_offset = -1; ++} ++ + static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset, + uint32_t value, int width, int be) + { + uint8_t *p; + +- trace_pflash_data_write(pfl->name, offset, width, value, pfl->counter); +- p = pfl->storage + offset; ++ if (pfl->blk_offset != -1) { ++ /* block write: redirect writes to block update buffer */ ++ if ((offset < pfl->blk_offset) || ++ (offset + width > pfl->blk_offset + pfl->writeblock_size)) { ++ pfl->status |= 0x10; /* Programming error */ ++ return; ++ } ++ trace_pflash_data_write_block(pfl->name, offset, width, value, ++ pfl->counter); ++ p = pfl->blk_bytes + (offset - pfl->blk_offset); ++ } else { ++ /* write directly to storage */ ++ trace_pflash_data_write(pfl->name, offset, width, value); ++ p = pfl->storage + offset; ++ } + + if (be) { + stn_be_p(p, width, value); +@@ -503,9 +572,9 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + } else { + value = extract32(value, 0, pfl->bank_width * 8); + } +- trace_pflash_write_block(pfl->name, value); + pfl->counter = value; + pfl->wcycle++; ++ pflash_blk_write_start(pfl, offset); + break; + case 0x60: + if (cmd == 0xd0) { +@@ -536,12 +605,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + switch (pfl->cmd) { + case 0xe8: /* Block write */ + /* FIXME check @offset, @width */ +- if (!pfl->ro) { +- /* +- * FIXME writing straight to memory is *wrong*. We +- * should write to a buffer, and flush it to memory +- * only on confirm command (see below). +- */ ++ if (!pfl->ro && (pfl->blk_offset != -1)) { + pflash_data_write(pfl, offset, value, width, be); + } else { + pfl->status |= 0x10; /* Programming error */ +@@ -550,18 +614,8 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + pfl->status |= 0x80; + + if (!pfl->counter) { +- hwaddr mask = pfl->writeblock_size - 1; +- mask = ~mask; +- + trace_pflash_write(pfl->name, "block write finished"); + pfl->wcycle++; +- if (!pfl->ro) { +- /* Flush the entire write buffer onto backing storage. */ +- /* FIXME premature! */ +- pflash_update(pfl, offset & mask, pfl->writeblock_size); +- } else { +- pfl->status |= 0x10; /* Programming error */ +- } + } + + pfl->counter--; +@@ -573,20 +627,17 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + case 3: /* Confirm mode */ + switch (pfl->cmd) { + case 0xe8: /* Block write */ +- if (cmd == 0xd0) { +- /* FIXME this is where we should write out the buffer */ ++ if ((cmd == 0xd0) && !(pfl->status & 0x10)) { ++ pflash_blk_write_flush(pfl); + pfl->wcycle = 0; + pfl->status |= 0x80; + } else { +- qemu_log_mask(LOG_UNIMP, +- "%s: Aborting write to buffer not implemented," +- " the data is already written to storage!\n" +- "Flash device reset into READ mode.\n", +- __func__); ++ pflash_blk_write_abort(pfl); + goto mode_read_array; + } + break; + default: ++ pflash_blk_write_abort(pfl); + goto error_flash; + } + break; +@@ -820,6 +871,9 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) + pfl->cmd = 0x00; + pfl->status = 0x80; /* WSM ready */ + pflash_cfi01_fill_cfi_table(pfl); ++ ++ pfl->blk_bytes = g_malloc(pfl->writeblock_size); ++ pfl->blk_offset = -1; + } + + static void pflash_cfi01_system_reset(DeviceState *dev) +@@ -839,6 +893,8 @@ static void pflash_cfi01_system_reset(DeviceState *dev) + * This model deliberately ignores this delay. + */ + pfl->status = 0x80; ++ ++ pfl->blk_offset = -1; + } + + static Property pflash_cfi01_properties[] = { +diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c +index 2a99b28..6fa56f1 100644 +--- a/hw/block/pflash_cfi02.c ++++ b/hw/block/pflash_cfi02.c +@@ -546,7 +546,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value, + } + goto reset_flash; + } +- trace_pflash_data_write(pfl->name, offset, width, value, 0); ++ trace_pflash_data_write(pfl->name, offset, width, value); + if (!pfl->ro) { + p = (uint8_t *)pfl->storage + offset; + if (pfl->be) { +diff --git a/hw/block/trace-events b/hw/block/trace-events +index bab21d3..cc9a9f2 100644 +--- a/hw/block/trace-events ++++ b/hw/block/trace-events +@@ -12,7 +12,8 @@ fdctrl_tc_pulse(int level) "TC pulse: %u" + pflash_chip_erase_invalid(const char *name, uint64_t offset) "%s: chip erase: invalid address 0x%" PRIx64 + pflash_chip_erase_start(const char *name) "%s: start chip erase" + pflash_data_read(const char *name, uint64_t offset, unsigned size, uint32_t value) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x" +-pflash_data_write(const char *name, uint64_t offset, unsigned size, uint32_t value, uint64_t counter) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x counter:0x%016"PRIx64 ++pflash_data_write(const char *name, uint64_t offset, unsigned size, uint32_t value) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x" ++pflash_data_write_block(const char *name, uint64_t offset, unsigned size, uint32_t value, uint64_t counter) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x counter:0x%016"PRIx64 + pflash_device_id(const char *name, uint16_t id) "%s: read device ID: 0x%04x" + pflash_device_info(const char *name, uint64_t offset) "%s: read device information offset:0x%04" PRIx64 + pflash_erase_complete(const char *name) "%s: sector erase complete" +@@ -32,7 +33,9 @@ pflash_unlock0_failed(const char *name, uint64_t offset, uint8_t cmd, uint16_t a + pflash_unlock1_failed(const char *name, uint64_t offset, uint8_t cmd) "%s: unlock0 failed 0x%" PRIx64 " 0x%02x" + pflash_unsupported_device_configuration(const char *name, uint8_t width, uint8_t max) "%s: unsupported device configuration: device_width:%d max_device_width:%d" + pflash_write(const char *name, const char *str) "%s: %s" +-pflash_write_block(const char *name, uint32_t value) "%s: block write: bytes:0x%x" ++pflash_write_block_start(const char *name, uint32_t value) "%s: block write start: bytes:0x%x" ++pflash_write_block_flush(const char *name) "%s: block write flush" ++pflash_write_block_abort(const char *name) "%s: block write abort" + pflash_write_block_erase(const char *name, uint64_t offset, uint64_t len) "%s: block erase offset:0x%" PRIx64 " bytes:0x%" PRIx64 + pflash_write_failed(const char *name, uint64_t offset, uint8_t cmd) "%s: command failed 0x%" PRIx64 " 0x%02x" + pflash_write_invalid(const char *name, uint8_t cmd) "%s: invalid write for command 0x%02x" +-- +1.8.3.1 + diff --git a/0042-migration-rdma-define-htonll-ntohll-only-if-not-pred.patch b/0042-migration-rdma-define-htonll-ntohll-only-if-not-pred.patch new file mode 100644 index 0000000000000000000000000000000000000000..71aaa0fd17985488506e2cdae23f23c6bee8d018 --- /dev/null +++ b/0042-migration-rdma-define-htonll-ntohll-only-if-not-pred.patch @@ -0,0 +1,50 @@ +From 3f675950dffd879ea35d387c0b6aa2136879d25f Mon Sep 17 00:00:00 2001 +From: Nick Briggs +Date: Thu, 11 Jan 2024 13:20:17 -0500 +Subject: [PATCH 047/293] migration/rdma: define htonll/ntohll only if not + predefined + +Solaris has #defines for htonll and ntohll which cause syntax errors +when compiling code that attempts to (re)define these functions.. + +Signed-off-by: Nick Briggs +Link: https://lore.kernel.org/r/65a04a7d.497ab3.3e7bef1f@gateway.sonic.net +Signed-off-by: Peter Xu +(cherry picked from commit 44ce1b5d2fc77343f6a318cb3de613336a240048) +Signed-off-by: Michael Tokarev +--- + migration/rdma.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/migration/rdma.c b/migration/rdma.c +index 04debab..4141c0b 100644 +--- a/migration/rdma.c ++++ b/migration/rdma.c +@@ -238,6 +238,7 @@ static const char *control_desc(unsigned int rdma_control) + return strs[rdma_control]; + } + ++#if !defined(htonll) + static uint64_t htonll(uint64_t v) + { + union { uint32_t lv[2]; uint64_t llv; } u; +@@ -245,13 +246,16 @@ static uint64_t htonll(uint64_t v) + u.lv[1] = htonl(v & 0xFFFFFFFFULL); + return u.llv; + } ++#endif + ++#if !defined(ntohll) + static uint64_t ntohll(uint64_t v) + { + union { uint32_t lv[2]; uint64_t llv; } u; + u.llv = v; + return ((uint64_t)ntohl(u.lv[0]) << 32) | (uint64_t) ntohl(u.lv[1]); + } ++#endif + + static void dest_block_to_network(RDMADestBlock *db) + { +-- +1.8.3.1 + diff --git a/0043-hw-scsi-esp-pci-use-correct-address-register-for-PCI.patch b/0043-hw-scsi-esp-pci-use-correct-address-register-for-PCI.patch new file mode 100644 index 0000000000000000000000000000000000000000..7a5f961e92bceea4785261c5f7a3f65308fd876d --- /dev/null +++ b/0043-hw-scsi-esp-pci-use-correct-address-register-for-PCI.patch @@ -0,0 +1,50 @@ +From 2d81285db113ed85eba43a746dcd65b8fa5ada4e Mon Sep 17 00:00:00 2001 +From: Mark Cave-Ayland +Date: Fri, 12 Jan 2024 13:15:26 +0000 +Subject: [PATCH 048/293] hw/scsi/esp-pci: use correct address register for PCI + DMA transfers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The current code in esp_pci_dma_memory_rw() sets the DMA address to the value +of the DMA_SPA (Starting Physical Address) register which is incorrect: this +means that for each callback from the SCSI layer the DMA address is set back +to the starting address. + +In the case where only a single SCSI callback occurs (currently for transfer +lengths < 128kB) this works fine, however for larger transfers the DMA address +wraps back to the initial starting address, corrupting the buffer holding the +data transferred to the guest. + +Fix esp_pci_dma_memory_rw() to use the DMA_WAC (Working Address Counter) for +the DMA address which is correctly incremented across multiple SCSI layer +transfers. + +Signed-off-by: Mark Cave-Ayland +Reviewed-by: Guenter Roeck +Tested-by: Guenter Roeck +Message-ID: <20240112131529.515642-2-mark.cave-ayland@ilande.co.uk> +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit 84a6835e004c257037492167d4f266dbb54dc33e) +Signed-off-by: Michael Tokarev +--- + hw/scsi/esp-pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c +index 4e890db..ac5d752 100644 +--- a/hw/scsi/esp-pci.c ++++ b/hw/scsi/esp-pci.c +@@ -275,7 +275,7 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len, + qemu_log_mask(LOG_UNIMP, "am53c974: MDL transfer not implemented\n"); + } + +- addr = pci->dma_regs[DMA_SPA]; ++ addr = pci->dma_regs[DMA_WAC]; + if (pci->dma_regs[DMA_WBC] < len) { + len = pci->dma_regs[DMA_WBC]; + } +-- +1.8.3.1 + diff --git a/0044-hw-scsi-esp-pci-generate-PCI-interrupt-from-separate.patch b/0044-hw-scsi-esp-pci-generate-PCI-interrupt-from-separate.patch new file mode 100644 index 0000000000000000000000000000000000000000..1b14aa0fc1308bf0ae0aa4c068af9d21ffcc4ace --- /dev/null +++ b/0044-hw-scsi-esp-pci-generate-PCI-interrupt-from-separate.patch @@ -0,0 +1,110 @@ +From d8e0533c94a7ddc481369742d73111531e2c38c4 Mon Sep 17 00:00:00 2001 +From: Mark Cave-Ayland +Date: Fri, 12 Jan 2024 13:15:27 +0000 +Subject: [PATCH 049/293] hw/scsi/esp-pci: generate PCI interrupt from separate + ESP and PCI sources +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The am53c974/dc390 PCI interrupt has two separate sources: the first is from the +internal ESP device, and the second is from the PCI DMA transfer logic. + +Update the ESP interrupt handler so that it sets DMA_STAT_SCSIINT rather than +driving the PCI IRQ directly, and introduce a new esp_pci_update_irq() function +to generate the correct PCI IRQ level. In particular this fixes spurious interrupts +being generated by setting DMA_STAT_DONE at the end of a transfer if DMA_CMD_INTE_D +isn't set in the DMA_CMD register. + +Signed-off-by: Mark Cave-Ayland +Reviewed-by: Guenter Roeck +Tested-by: Guenter Roeck +Message-ID: <20240112131529.515642-3-mark.cave-ayland@ilande.co.uk> +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit 6b41417d934b2640b7ccf893544d656eea92a2e7) +Signed-off-by: Michael Tokarev +--- + hw/scsi/esp-pci.c | 32 +++++++++++++++++++++++++++----- + 1 file changed, 27 insertions(+), 5 deletions(-) + +diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c +index ac5d752..d29c8c2 100644 +--- a/hw/scsi/esp-pci.c ++++ b/hw/scsi/esp-pci.c +@@ -77,6 +77,29 @@ struct PCIESPState { + ESPState esp; + }; + ++static void esp_pci_update_irq(PCIESPState *pci) ++{ ++ int scsi_level = !!(pci->dma_regs[DMA_STAT] & DMA_STAT_SCSIINT); ++ int dma_level = (pci->dma_regs[DMA_CMD] & DMA_CMD_INTE_D) ? ++ !!(pci->dma_regs[DMA_STAT] & DMA_STAT_DONE) : 0; ++ int level = scsi_level || dma_level; ++ ++ pci_set_irq(PCI_DEVICE(pci), level); ++} ++ ++static void esp_irq_handler(void *opaque, int irq_num, int level) ++{ ++ PCIESPState *pci = PCI_ESP(opaque); ++ ++ if (level) { ++ pci->dma_regs[DMA_STAT] |= DMA_STAT_SCSIINT; ++ } else { ++ pci->dma_regs[DMA_STAT] &= ~DMA_STAT_SCSIINT; ++ } ++ ++ esp_pci_update_irq(pci); ++} ++ + static void esp_pci_handle_idle(PCIESPState *pci, uint32_t val) + { + ESPState *s = &pci->esp; +@@ -151,6 +174,7 @@ static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val) + /* clear some bits on write */ + uint32_t mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE; + pci->dma_regs[DMA_STAT] &= ~(val & mask); ++ esp_pci_update_irq(pci); + } + break; + default: +@@ -161,17 +185,14 @@ static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val) + + static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr) + { +- ESPState *s = &pci->esp; + uint32_t val; + + val = pci->dma_regs[saddr]; + if (saddr == DMA_STAT) { +- if (s->rregs[ESP_RSTAT] & STAT_INT) { +- val |= DMA_STAT_SCSIINT; +- } + if (!(pci->sbac & SBAC_STATUS)) { + pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT | + DMA_STAT_DONE); ++ esp_pci_update_irq(pci); + } + } + +@@ -350,6 +371,7 @@ static void esp_pci_command_complete(SCSIRequest *req, size_t resid) + esp_command_complete(req, resid); + pci->dma_regs[DMA_WBC] = 0; + pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE; ++ esp_pci_update_irq(pci); + } + + static const struct SCSIBusInfo esp_pci_scsi_info = { +@@ -386,7 +408,7 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp) + "esp-io", 0x80); + + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io); +- s->irq = pci_allocate_irq(dev); ++ s->irq = qemu_allocate_irq(esp_irq_handler, pci, 0); + + scsi_bus_init(&s->bus, sizeof(s->bus), d, &esp_pci_scsi_info); + } +-- +1.8.3.1 + diff --git a/0045-hw-scsi-esp-pci-synchronise-setting-of-DMA_STAT_DONE.patch b/0045-hw-scsi-esp-pci-synchronise-setting-of-DMA_STAT_DONE.patch new file mode 100644 index 0000000000000000000000000000000000000000..5771485493fcfc23953826eb1e049d617b2419f7 --- /dev/null +++ b/0045-hw-scsi-esp-pci-synchronise-setting-of-DMA_STAT_DONE.patch @@ -0,0 +1,100 @@ +From 06a28b783bd406eacf452d9b0400719f3bc226c5 Mon Sep 17 00:00:00 2001 +From: Mark Cave-Ayland +Date: Fri, 12 Jan 2024 13:15:28 +0000 +Subject: [PATCH 050/293] hw/scsi/esp-pci: synchronise setting of DMA_STAT_DONE + with ESP completion interrupt +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The setting of DMA_STAT_DONE at the end of a DMA transfer can be configured to +generate an interrupt, however the Linux driver manually checks for DMA_STAT_DONE +being set and if it is, considers that a DMA transfer has completed. + +If DMA_STAT_DONE is set but the ESP device isn't indicating an interrupt then +the Linux driver considers this to be a spurious interrupt. However this can +occur in QEMU as there is a delay between the end of DMA transfer where +DMA_STAT_DONE is set, and the ESP device raising its completion interrupt. + +This appears to be an incorrect assumption in the Linux driver as the ESP and +PCI DMA interrupt sources are separate (and may not be raised exactly +together), however we can work around this by synchronising the setting of +DMA_STAT_DONE at the end of a DMA transfer with the ESP completion interrupt. + +In conjunction with the previous commit Linux is now able to correctly boot +from an am53c974 PCI SCSI device on the hppa C3700 machine without emitting +"iget: checksum invalid" and "Spurious irq, sreg=10" errors. + +Signed-off-by: Mark Cave-Ayland +Reviewed-by: Guenter Roeck +Tested-by: Guenter Roeck +Message-ID: <20240112131529.515642-4-mark.cave-ayland@ilande.co.uk> +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit 1e8e6644e063b20ad391140fae13d00ad7750b33) +Signed-off-by: Michael Tokarev +--- + hw/scsi/esp-pci.c | 28 +++++++++++++--------------- + 1 file changed, 13 insertions(+), 15 deletions(-) + +diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c +index d29c8c2..b1bd43b 100644 +--- a/hw/scsi/esp-pci.c ++++ b/hw/scsi/esp-pci.c +@@ -93,6 +93,18 @@ static void esp_irq_handler(void *opaque, int irq_num, int level) + + if (level) { + pci->dma_regs[DMA_STAT] |= DMA_STAT_SCSIINT; ++ ++ /* ++ * If raising the ESP IRQ to indicate end of DMA transfer, set ++ * DMA_STAT_DONE at the same time. In theory this should be done in ++ * esp_pci_dma_memory_rw(), however there is a delay between setting ++ * DMA_STAT_DONE and the ESP IRQ arriving which is visible to the ++ * guest that can cause confusion e.g. Linux ++ */ ++ if ((pci->dma_regs[DMA_CMD] & DMA_CMD_MASK) == 0x3 && ++ pci->dma_regs[DMA_WBC] == 0) { ++ pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE; ++ } + } else { + pci->dma_regs[DMA_STAT] &= ~DMA_STAT_SCSIINT; + } +@@ -306,9 +318,6 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len, + /* update status registers */ + pci->dma_regs[DMA_WBC] -= len; + pci->dma_regs[DMA_WAC] += len; +- if (pci->dma_regs[DMA_WBC] == 0) { +- pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE; +- } + } + + static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len) +@@ -363,24 +372,13 @@ static const VMStateDescription vmstate_esp_pci_scsi = { + } + }; + +-static void esp_pci_command_complete(SCSIRequest *req, size_t resid) +-{ +- ESPState *s = req->hba_private; +- PCIESPState *pci = container_of(s, PCIESPState, esp); +- +- esp_command_complete(req, resid); +- pci->dma_regs[DMA_WBC] = 0; +- pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE; +- esp_pci_update_irq(pci); +-} +- + static const struct SCSIBusInfo esp_pci_scsi_info = { + .tcq = false, + .max_target = ESP_MAX_DEVS, + .max_lun = 7, + + .transfer_data = esp_transfer_data, +- .complete = esp_pci_command_complete, ++ .complete = esp_command_complete, + .cancel = esp_request_cancelled, + }; + +-- +1.8.3.1 + diff --git a/0046-hw-scsi-esp-pci-set-DMA_STAT_BCMBLT-when-BLAST-comma.patch b/0046-hw-scsi-esp-pci-set-DMA_STAT_BCMBLT-when-BLAST-comma.patch new file mode 100644 index 0000000000000000000000000000000000000000..591ef5b087a2a15ff520cf3762f1e93cdc7e3bdf --- /dev/null +++ b/0046-hw-scsi-esp-pci-set-DMA_STAT_BCMBLT-when-BLAST-comma.patch @@ -0,0 +1,43 @@ +From 164e6f7d66adeaae9db54cefec9fca8941fe1e10 Mon Sep 17 00:00:00 2001 +From: Mark Cave-Ayland +Date: Fri, 12 Jan 2024 13:15:29 +0000 +Subject: [PATCH 051/293] hw/scsi/esp-pci: set DMA_STAT_BCMBLT when BLAST + command issued +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Even though the BLAST command isn't fully implemented in QEMU, the DMA_STAT_BCMBLT +bit should be set after the command has been issued to indicate that the command +has completed. + +This fixes an issue with the DC390 DOS driver which issues the BLAST command as +part of its normal error recovery routine at startup, and otherwise sits in a +tight loop waiting for DMA_STAT_BCMBLT to be set before continuing. + +Signed-off-by: Mark Cave-Ayland +Reviewed-by: Guenter Roeck +Tested-by: Guenter Roeck +Message-ID: <20240112131529.515642-5-mark.cave-ayland@ilande.co.uk> +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit c2d7de557d19ec76eb83b87b6bf77c8114e2f183) +Signed-off-by: Michael Tokarev +--- + hw/scsi/esp-pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c +index b1bd43b..51f0157 100644 +--- a/hw/scsi/esp-pci.c ++++ b/hw/scsi/esp-pci.c +@@ -124,6 +124,7 @@ static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val) + { + trace_esp_pci_dma_blast(val); + qemu_log_mask(LOG_UNIMP, "am53c974: cmd BLAST not implemented\n"); ++ pci->dma_regs[DMA_STAT] |= DMA_STAT_BCMBLT; + } + + static void esp_pci_handle_abort(PCIESPState *pci, uint32_t val) +-- +1.8.3.1 + diff --git a/0047-s390x-pci-avoid-double-enable-disable-of-aif.patch b/0047-s390x-pci-avoid-double-enable-disable-of-aif.patch new file mode 100644 index 0000000000000000000000000000000000000000..42cc6c8735e2474b93b7eae400f34a6cefb210d0 --- /dev/null +++ b/0047-s390x-pci-avoid-double-enable-disable-of-aif.patch @@ -0,0 +1,91 @@ +From 9d6dd12b1d60f26fcefeb35a5fc27a6bdce19b65 Mon Sep 17 00:00:00 2001 +From: Matthew Rosato +Date: Thu, 18 Jan 2024 13:51:49 -0500 +Subject: [PATCH 052/293] s390x/pci: avoid double enable/disable of aif +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use a flag to keep track of whether AIF is currently enabled. This can be +used to avoid enabling/disabling AIF multiple times as well as to determine +whether or not it should be disabled during reset processing. + +Fixes: d0bc7091c2 ("s390x/pci: enable adapter event notification for interpreted devices") +Reported-by: Cédric Le Goater +Reviewed-by: Eric Farman +Signed-off-by: Matthew Rosato +Message-ID: <20240118185151.265329-2-mjrosato@linux.ibm.com> +Reviewed-by: Cédric Le Goater +Signed-off-by: Thomas Huth +(cherry picked from commit 07b2c8e034d80ff92e202405c494d2ff80fcf848) +Signed-off-by: Michael Tokarev +--- + hw/s390x/s390-pci-kvm.c | 25 +++++++++++++++++++++++-- + include/hw/s390x/s390-pci-bus.h | 1 + + 2 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/hw/s390x/s390-pci-kvm.c b/hw/s390x/s390-pci-kvm.c +index ff41e41..1ee5104 100644 +--- a/hw/s390x/s390-pci-kvm.c ++++ b/hw/s390x/s390-pci-kvm.c +@@ -27,6 +27,7 @@ bool s390_pci_kvm_interp_allowed(void) + + int s390_pci_kvm_aif_enable(S390PCIBusDevice *pbdev, ZpciFib *fib, bool assist) + { ++ int rc; + struct kvm_s390_zpci_op args = { + .fh = pbdev->fh, + .op = KVM_S390_ZPCIOP_REG_AEN, +@@ -38,15 +39,35 @@ int s390_pci_kvm_aif_enable(S390PCIBusDevice *pbdev, ZpciFib *fib, bool assist) + .u.reg_aen.flags = (assist) ? 0 : KVM_S390_ZPCIOP_REGAEN_HOST + }; + +- return kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args); ++ if (pbdev->aif) { ++ return -EINVAL; ++ } ++ ++ rc = kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args); ++ if (rc == 0) { ++ pbdev->aif = true; ++ } ++ ++ return rc; + } + + int s390_pci_kvm_aif_disable(S390PCIBusDevice *pbdev) + { ++ int rc; ++ + struct kvm_s390_zpci_op args = { + .fh = pbdev->fh, + .op = KVM_S390_ZPCIOP_DEREG_AEN + }; + +- return kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args); ++ if (!pbdev->aif) { ++ return -EINVAL; ++ } ++ ++ rc = kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args); ++ if (rc == 0) { ++ pbdev->aif = false; ++ } ++ ++ return rc; + } +diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h +index b1bdbea..435e788 100644 +--- a/include/hw/s390x/s390-pci-bus.h ++++ b/include/hw/s390x/s390-pci-bus.h +@@ -361,6 +361,7 @@ struct S390PCIBusDevice { + bool unplug_requested; + bool interp; + bool forwarding_assist; ++ bool aif; + QTAILQ_ENTRY(S390PCIBusDevice) link; + }; + +-- +1.8.3.1 + diff --git a/0048-s390x-pci-refresh-fh-before-disabling-aif.patch b/0048-s390x-pci-refresh-fh-before-disabling-aif.patch new file mode 100644 index 0000000000000000000000000000000000000000..1019f5d639ee03e892f7f0c450d401c6e3a22a7a --- /dev/null +++ b/0048-s390x-pci-refresh-fh-before-disabling-aif.patch @@ -0,0 +1,56 @@ +From c2985e38d803e62091f77ecb372c9c5fdf997239 Mon Sep 17 00:00:00 2001 +From: Matthew Rosato +Date: Thu, 18 Jan 2024 13:51:50 -0500 +Subject: [PATCH 053/293] s390x/pci: refresh fh before disabling aif +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Typically we refresh the host fh during CLP enable, however it's possible +that the device goes through multiple reset events before the guest +performs another CLP enable. Let's handle this for now by refreshing the +host handle from vfio before disabling aif. + +Fixes: 03451953c7 ("s390x/pci: reset ISM passthrough devices on shutdown and system reset") +Reported-by: Cédric Le Goater +Reviewed-by: Eric Farman +Signed-off-by: Matthew Rosato +Message-ID: <20240118185151.265329-3-mjrosato@linux.ibm.com> +Reviewed-by: Cédric Le Goater +Signed-off-by: Thomas Huth +(cherry picked from commit 30e35258e25c75c9d799c34fd89afcafffb37084) +Signed-off-by: Michael Tokarev +--- + hw/s390x/s390-pci-kvm.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/hw/s390x/s390-pci-kvm.c b/hw/s390x/s390-pci-kvm.c +index 1ee5104..9eef4fc 100644 +--- a/hw/s390x/s390-pci-kvm.c ++++ b/hw/s390x/s390-pci-kvm.c +@@ -18,6 +18,7 @@ + #include "hw/s390x/s390-pci-bus.h" + #include "hw/s390x/s390-pci-kvm.h" + #include "hw/s390x/s390-pci-inst.h" ++#include "hw/s390x/s390-pci-vfio.h" + #include "cpu_models.h" + + bool s390_pci_kvm_interp_allowed(void) +@@ -64,6 +65,14 @@ int s390_pci_kvm_aif_disable(S390PCIBusDevice *pbdev) + return -EINVAL; + } + ++ /* ++ * The device may have already been reset but we still want to relinquish ++ * the guest ISC, so always be sure to use an up-to-date host fh. ++ */ ++ if (!s390_pci_get_host_fh(pbdev, &args.fh)) { ++ return -EPERM; ++ } ++ + rc = kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args); + if (rc == 0) { + pbdev->aif = false; +-- +1.8.3.1 + diff --git a/0049-s390x-pci-drive-ISM-reset-from-subsystem-reset.patch b/0049-s390x-pci-drive-ISM-reset-from-subsystem-reset.patch new file mode 100644 index 0000000000000000000000000000000000000000..bc3014f41a675878b0501c103e30d3bd7dc20a7e --- /dev/null +++ b/0049-s390x-pci-drive-ISM-reset-from-subsystem-reset.patch @@ -0,0 +1,122 @@ +From 003d0c7eb449231b0cd9870e295f04840a9b5c05 Mon Sep 17 00:00:00 2001 +From: Matthew Rosato +Date: Thu, 18 Jan 2024 13:51:51 -0500 +Subject: [PATCH 054/293] s390x/pci: drive ISM reset from subsystem reset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ISM devices are sensitive to manipulation of the IOMMU, so the ISM device +needs to be reset before the vfio-pci device is reset (triggering a full +UNMAP). In order to ensure this occurs, trigger ISM device resets from +subsystem_reset before triggering the PCI bus reset (which will also +trigger vfio-pci reset). This only needs to be done for ISM devices +which were enabled for use by the guest. +Further, ensure that AIF is disabled as part of the reset event. + +Fixes: ef1535901a ("s390x: do a subsystem reset before the unprotect on reboot") +Fixes: 03451953c7 ("s390x/pci: reset ISM passthrough devices on shutdown and system reset") +Reported-by: Cédric Le Goater +Signed-off-by: Matthew Rosato +Message-ID: <20240118185151.265329-4-mjrosato@linux.ibm.com> +Reviewed-by: Eric Farman +Reviewed-by: Cédric Le Goater +Signed-off-by: Thomas Huth +(cherry picked from commit 68c691ca99a2538d6a53a70ce8a9ce06ee307ff1) +Signed-off-by: Michael Tokarev +--- + hw/s390x/s390-pci-bus.c | 26 +++++++++++++++++--------- + hw/s390x/s390-virtio-ccw.c | 8 ++++++++ + include/hw/s390x/s390-pci-bus.h | 1 + + 3 files changed, 26 insertions(+), 9 deletions(-) + +diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c +index 347580e..3e57d5f 100644 +--- a/hw/s390x/s390-pci-bus.c ++++ b/hw/s390x/s390-pci-bus.c +@@ -151,20 +151,12 @@ static void s390_pci_shutdown_notifier(Notifier *n, void *opaque) + pci_device_reset(pbdev->pdev); + } + +-static void s390_pci_reset_cb(void *opaque) +-{ +- S390PCIBusDevice *pbdev = opaque; +- +- pci_device_reset(pbdev->pdev); +-} +- + static void s390_pci_perform_unplug(S390PCIBusDevice *pbdev) + { + HotplugHandler *hotplug_ctrl; + + if (pbdev->pft == ZPCI_PFT_ISM) { + notifier_remove(&pbdev->shutdown_notifier); +- qemu_unregister_reset(s390_pci_reset_cb, pbdev); + } + + /* Unplug the PCI device */ +@@ -1132,7 +1124,6 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + if (pbdev->pft == ZPCI_PFT_ISM) { + pbdev->shutdown_notifier.notify = s390_pci_shutdown_notifier; + qemu_register_shutdown_notifier(&pbdev->shutdown_notifier); +- qemu_register_reset(s390_pci_reset_cb, pbdev); + } + } else { + pbdev->fh |= FH_SHM_EMUL; +@@ -1279,6 +1270,23 @@ static void s390_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev, + pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, s->bus_no, 1); + } + ++void s390_pci_ism_reset(void) ++{ ++ S390pciState *s = s390_get_phb(); ++ ++ S390PCIBusDevice *pbdev, *next; ++ ++ /* Trigger reset event for each passthrough ISM device currently in-use */ ++ QTAILQ_FOREACH_SAFE(pbdev, &s->zpci_devs, link, next) { ++ if (pbdev->interp && pbdev->pft == ZPCI_PFT_ISM && ++ pbdev->fh & FH_MASK_ENABLE) { ++ s390_pci_kvm_aif_disable(pbdev); ++ ++ pci_device_reset(pbdev->pdev); ++ } ++ } ++} ++ + static void s390_pcihost_reset(DeviceState *dev) + { + S390pciState *s = S390_PCI_HOST_BRIDGE(dev); +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index 7262725..2d6b866 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -118,6 +118,14 @@ static void subsystem_reset(void) + DeviceState *dev; + int i; + ++ /* ++ * ISM firmware is sensitive to unexpected changes to the IOMMU, which can ++ * occur during reset of the vfio-pci device (unmap of entire aperture). ++ * Ensure any passthrough ISM devices are reset now, while CPUs are paused ++ * but before vfio-pci cleanup occurs. ++ */ ++ s390_pci_ism_reset(); ++ + for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) { + dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL)); + if (dev) { +diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h +index 435e788..2c43ea1 100644 +--- a/include/hw/s390x/s390-pci-bus.h ++++ b/include/hw/s390x/s390-pci-bus.h +@@ -401,5 +401,6 @@ S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s, + const char *target); + S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s, + S390PCIBusDevice *pbdev); ++void s390_pci_ism_reset(void); + + #endif +-- +1.8.3.1 + diff --git a/0050-acpi-tests-avocado-bits-wait-for-200-seconds-for-SHU.patch b/0050-acpi-tests-avocado-bits-wait-for-200-seconds-for-SHU.patch new file mode 100644 index 0000000000000000000000000000000000000000..451a598f23c4da31a0e5c9f4038b493b7188504d --- /dev/null +++ b/0050-acpi-tests-avocado-bits-wait-for-200-seconds-for-SHU.patch @@ -0,0 +1,65 @@ +From 5e4e438f9d602f8089e88252e58c523d77947ee1 Mon Sep 17 00:00:00 2001 +From: Ani Sinha +Date: Wed, 17 Jan 2024 09:55:56 +0530 +Subject: [PATCH 055/293] acpi/tests/avocado/bits: wait for 200 seconds for + SHUTDOWN event from bits VM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +By default, the timeout to receive any specified event from the QEMU VM is 60 +seconds set by the python avocado test framework. Please see event_wait() and +events_wait() in python/qemu/machine/machine.py. If the matching event is not +triggered within that interval, an asyncio.TimeoutError is generated. Since the +timeout for the bits avocado test is 200 secs, we need to make event_wait() +timeout of the same value as well so that an early timeout is not triggered by +the avocado framework. + +CC: peter.maydell@linaro.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2077 +Signed-off-by: Ani Sinha +Reviewed-by: Daniel P. Berrangé +Message-id: 20240117042556.3360190-1-anisinha@redhat.com +Signed-off-by: Peter Maydell +(cherry picked from commit 7ef4c41e91d59d72a3b8bc022a6cb3e81787a50a) +Signed-off-by: Michael Tokarev +--- + tests/avocado/acpi-bits.py | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/tests/avocado/acpi-bits.py b/tests/avocado/acpi-bits.py +index 68b9e98..efe4f52 100644 +--- a/tests/avocado/acpi-bits.py ++++ b/tests/avocado/acpi-bits.py +@@ -54,6 +54,8 @@ + 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 which(tool): + """ looks up the full path for @tool, returns None if not found +@@ -133,7 +135,7 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes + + """ + # in slower systems the test can take as long as 3 minutes to complete. +- timeout = 200 ++ timeout = BITS_TIMEOUT + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) +@@ -400,7 +402,8 @@ def test_acpi_smbios_bits(self): + + # biosbits has been configured to run all the specified test suites + # in batch mode and then automatically initiate a vm shutdown. +- # Rely on avocado's unit test timeout. +- self._vm.event_wait('SHUTDOWN') ++ # Set timeout to BITS_TIMEOUT for SHUTDOWN event from bits VM at par ++ # with the avocado test timeout. ++ self._vm.event_wait('SHUTDOWN', timeout=BITS_TIMEOUT) + self._vm.wait(timeout=None) + self.parse_log() +-- +1.8.3.1 + diff --git a/0051-accel-tcg-Revert-mapping-of-PCREL-translation-block-.patch b/0051-accel-tcg-Revert-mapping-of-PCREL-translation-block-.patch new file mode 100644 index 0000000000000000000000000000000000000000..7eabf694f156d9af2382873d197b869a71507876 --- /dev/null +++ b/0051-accel-tcg-Revert-mapping-of-PCREL-translation-block-.patch @@ -0,0 +1,91 @@ +From ef74024b76bf285e247add8538c11cb3c7399a1a Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Tue, 23 Jan 2024 12:33:31 +0100 +Subject: [PATCH 056/293] accel/tcg: Revert mapping of PCREL translation block + to multiple virtual addresses + +This is causing regressions that have not been analyzed yet. Revert the +change on stable branches. + +Cc: qemu-stable@nongnu.org +Cc: Michael Tokarev +Related: https://gitlab.com/qemu-project/qemu/-/issues/2092 +Signed-off-by: Paolo Bonzini +Signed-off-by: Michael Tokarev +--- + accel/tcg/cpu-exec.c | 4 ++-- + accel/tcg/tb-maint.c | 6 +++--- + accel/tcg/translate-all.c | 4 +--- + 3 files changed, 6 insertions(+), 8 deletions(-) + +diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c +index c938eb9..6a4af14 100644 +--- a/accel/tcg/cpu-exec.c ++++ b/accel/tcg/cpu-exec.c +@@ -183,7 +183,7 @@ static bool tb_lookup_cmp(const void *p, const void *d) + const TranslationBlock *tb = p; + const struct tb_desc *desc = d; + +- if ((tb_cflags(tb) & CF_PCREL || tb->pc == desc->pc) && ++ if (tb->pc == desc->pc && + tb_page_addr0(tb) == desc->page_addr0 && + tb->cs_base == desc->cs_base && + tb->flags == desc->flags && +@@ -233,7 +233,7 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, vaddr pc, + return NULL; + } + desc.page_addr0 = phys_pc; +- h = tb_hash_func(phys_pc, (cflags & CF_PCREL ? 0 : pc), ++ h = tb_hash_func(phys_pc, pc, + flags, cs_base, cflags); + return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp); + } +diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c +index 3d2a896..0d069a0 100644 +--- a/accel/tcg/tb-maint.c ++++ b/accel/tcg/tb-maint.c +@@ -47,7 +47,7 @@ static bool tb_cmp(const void *ap, const void *bp) + const TranslationBlock *a = ap; + const TranslationBlock *b = bp; + +- return ((tb_cflags(a) & CF_PCREL || a->pc == b->pc) && ++ return (a->pc == b->pc && + a->cs_base == b->cs_base && + a->flags == b->flags && + (tb_cflags(a) & ~CF_INVALID) == (tb_cflags(b) & ~CF_INVALID) && +@@ -916,7 +916,7 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list) + + /* remove the TB from the hash list */ + phys_pc = tb_page_addr0(tb); +- h = tb_hash_func(phys_pc, (orig_cflags & CF_PCREL ? 0 : tb->pc), ++ h = tb_hash_func(phys_pc, tb->pc, + tb->flags, tb->cs_base, orig_cflags); + if (!qht_remove(&tb_ctx.htable, tb, h)) { + return; +@@ -983,7 +983,7 @@ TranslationBlock *tb_link_page(TranslationBlock *tb) + tb_record(tb); + + /* add in the hash table */ +- h = tb_hash_func(tb_page_addr0(tb), (tb->cflags & CF_PCREL ? 0 : tb->pc), ++ h = tb_hash_func(tb_page_addr0(tb), tb->pc, + tb->flags, tb->cs_base, tb->cflags); + qht_insert(&tb_ctx.htable, tb, h, &existing_tb); + +diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c +index 79a88f5..c1708af 100644 +--- a/accel/tcg/translate-all.c ++++ b/accel/tcg/translate-all.c +@@ -327,9 +327,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, + + gen_code_buf = tcg_ctx->code_gen_ptr; + tb->tc.ptr = tcg_splitwx_to_rx(gen_code_buf); +- if (!(cflags & CF_PCREL)) { +- tb->pc = pc; +- } ++ tb->pc = pc; + tb->cs_base = cs_base; + tb->flags = flags; + tb->cflags = cflags; +-- +1.8.3.1 + diff --git a/0052-tcg-s390x-Fix-encoding-of-VRIc-VRSa-VRSc-insns.patch b/0052-tcg-s390x-Fix-encoding-of-VRIc-VRSa-VRSc-insns.patch new file mode 100644 index 0000000000000000000000000000000000000000..57a9c09e270bceddf20c351b34b81cf6e52d3b6d --- /dev/null +++ b/0052-tcg-s390x-Fix-encoding-of-VRIc-VRSa-VRSc-insns.patch @@ -0,0 +1,62 @@ +From 005d7236dba9434afdbcb8e2e174364cd330a2c4 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Wed, 17 Jan 2024 21:13:35 +0000 +Subject: [PATCH 057/293] tcg/s390x: Fix encoding of VRIc, VRSa, VRSc insns + +While the format names the second vector register 'v3', +it is still in the second position (bits 12-15) and +the argument to RXB must match. + +Example error: + - e7 00 00 10 2a 33 verllf %v16,%v0,16 + + e7 00 00 10 2c 33 verllf %v16,%v16,16 + +Cc: qemu-stable@nongnu.org +Reported-by: Michael Tokarev +Fixes: 22cb37b4172 ("tcg/s390x: Implement vector shift operations") +Fixes: 79cada8693d ("tcg/s390x: Implement tcg_out_dup*_vec") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2054 +Reviewed-by: Thomas Huth +Tested-by: Michael Tokarev +Message-Id: <20240117213646.159697-2-richard.henderson@linaro.org> +Signed-off-by: Richard Henderson +(cherry picked from commit c1ddc18f37108498f45d57afd6bf33a23b703648) +Signed-off-by: Michael Tokarev +--- + tcg/s390x/tcg-target.c.inc | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc +index fbee43d..7f6b84a 100644 +--- a/tcg/s390x/tcg-target.c.inc ++++ b/tcg/s390x/tcg-target.c.inc +@@ -683,7 +683,7 @@ static void tcg_out_insn_VRIc(TCGContext *s, S390Opcode op, + tcg_debug_assert(is_vector_reg(v3)); + tcg_out16(s, (op & 0xff00) | ((v1 & 0xf) << 4) | (v3 & 0xf)); + tcg_out16(s, i2); +- tcg_out16(s, (op & 0x00ff) | RXB(v1, 0, v3, 0) | (m4 << 12)); ++ tcg_out16(s, (op & 0x00ff) | RXB(v1, v3, 0, 0) | (m4 << 12)); + } + + static void tcg_out_insn_VRRa(TCGContext *s, S390Opcode op, +@@ -738,7 +738,7 @@ static void tcg_out_insn_VRSa(TCGContext *s, S390Opcode op, TCGReg v1, + tcg_debug_assert(is_vector_reg(v3)); + tcg_out16(s, (op & 0xff00) | ((v1 & 0xf) << 4) | (v3 & 0xf)); + tcg_out16(s, b2 << 12 | d2); +- tcg_out16(s, (op & 0x00ff) | RXB(v1, 0, v3, 0) | (m4 << 12)); ++ tcg_out16(s, (op & 0x00ff) | RXB(v1, v3, 0, 0) | (m4 << 12)); + } + + static void tcg_out_insn_VRSb(TCGContext *s, S390Opcode op, TCGReg v1, +@@ -762,7 +762,7 @@ static void tcg_out_insn_VRSc(TCGContext *s, S390Opcode op, TCGReg r1, + tcg_debug_assert(is_vector_reg(v3)); + tcg_out16(s, (op & 0xff00) | (r1 << 4) | (v3 & 0xf)); + tcg_out16(s, b2 << 12 | d2); +- tcg_out16(s, (op & 0x00ff) | RXB(0, 0, v3, 0) | (m4 << 12)); ++ tcg_out16(s, (op & 0x00ff) | RXB(0, v3, 0, 0) | (m4 << 12)); + } + + static void tcg_out_insn_VRX(TCGContext *s, S390Opcode op, TCGReg v1, +-- +1.8.3.1 + diff --git a/0053-coroutine-ucontext-Save-fake-stack-for-pooled-corout.patch b/0053-coroutine-ucontext-Save-fake-stack-for-pooled-corout.patch new file mode 100644 index 0000000000000000000000000000000000000000..4008edfb5957c5b68c83dc5d38343c9810421bb0 --- /dev/null +++ b/0053-coroutine-ucontext-Save-fake-stack-for-pooled-corout.patch @@ -0,0 +1,108 @@ +From f413f9fcc923083a7db038e32964148cf74134e6 Mon Sep 17 00:00:00 2001 +From: Akihiko Odaki +Date: Wed, 17 Jan 2024 16:06:02 +0900 +Subject: [PATCH 058/293] coroutine-ucontext: Save fake stack for pooled + coroutine +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Coroutine may be pooled even after COROUTINE_TERMINATE if +CONFIG_COROUTINE_POOL is enabled and fake stack should be saved in +such a case to keep AddressSanitizerUseAfterReturn working. Even worse, +I'm seeing stack corruption without fake stack being saved. + +Signed-off-by: Akihiko Odaki +Reviewed-by: Marc-André Lureau +Signed-off-by: Stefan Hajnoczi +Message-ID: <20240117-asan-v2-1-26f9e1ea6e72@daynix.com> +(cherry picked from commit d9945ccda08ef83b09ac7725b6ee2d1959f2c0c0) +Signed-off-by: Michael Tokarev +--- + util/coroutine-ucontext.c | 35 ++++++++++++++++++++++++++--------- + 1 file changed, 26 insertions(+), 9 deletions(-) + +diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c +index 7b304c7..8ef603d 100644 +--- a/util/coroutine-ucontext.c ++++ b/util/coroutine-ucontext.c +@@ -119,13 +119,11 @@ void finish_switch_fiber(void *fake_stack_save) + + /* always_inline is required to avoid TSan runtime fatal errors. */ + static inline __attribute__((always_inline)) +-void start_switch_fiber_asan(CoroutineAction action, void **fake_stack_save, ++void start_switch_fiber_asan(void **fake_stack_save, + const void *bottom, size_t size) + { + #ifdef CONFIG_ASAN +- __sanitizer_start_switch_fiber( +- action == COROUTINE_TERMINATE ? NULL : fake_stack_save, +- bottom, size); ++ __sanitizer_start_switch_fiber(fake_stack_save, bottom, size); + #endif + } + +@@ -165,7 +163,7 @@ static void coroutine_trampoline(int i0, int i1) + if (!sigsetjmp(self->env, 0)) { + CoroutineUContext *leaderp = get_ptr_leader(); + +- start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save, ++ start_switch_fiber_asan(&fake_stack_save, + leaderp->stack, leaderp->stack_size); + start_switch_fiber_tsan(&fake_stack_save, self, true); /* true=caller */ + siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); +@@ -226,8 +224,7 @@ Coroutine *qemu_coroutine_new(void) + + /* swapcontext() in, siglongjmp() back out */ + if (!sigsetjmp(old_env, 0)) { +- start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save, co->stack, +- co->stack_size); ++ start_switch_fiber_asan(&fake_stack_save, co->stack, co->stack_size); + start_switch_fiber_tsan(&fake_stack_save, + co, false); /* false=not caller */ + +@@ -269,10 +266,28 @@ static inline void valgrind_stack_deregister(CoroutineUContext *co) + #endif + #endif + ++#if defined(CONFIG_ASAN) && defined(CONFIG_COROUTINE_POOL) ++static void coroutine_fn terminate_asan(void *opaque) ++{ ++ CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, opaque); ++ ++ set_current(opaque); ++ start_switch_fiber_asan(NULL, to->stack, to->stack_size); ++ G_STATIC_ASSERT(!IS_ENABLED(CONFIG_TSAN)); ++ siglongjmp(to->env, COROUTINE_ENTER); ++} ++#endif ++ + void qemu_coroutine_delete(Coroutine *co_) + { + CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); + ++#if defined(CONFIG_ASAN) && defined(CONFIG_COROUTINE_POOL) ++ co_->entry_arg = qemu_coroutine_self(); ++ co_->entry = terminate_asan; ++ qemu_coroutine_switch(co_->entry_arg, co_, COROUTINE_ENTER); ++#endif ++ + #ifdef CONFIG_VALGRIND_H + valgrind_stack_deregister(co); + #endif +@@ -305,8 +320,10 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, + + ret = sigsetjmp(from->env, 0); + if (ret == 0) { +- start_switch_fiber_asan(action, &fake_stack_save, to->stack, +- to->stack_size); ++ start_switch_fiber_asan(IS_ENABLED(CONFIG_COROUTINE_POOL) || ++ action != COROUTINE_TERMINATE ? ++ &fake_stack_save : NULL, ++ to->stack, to->stack_size); + start_switch_fiber_tsan(&fake_stack_save, + to, false); /* false=not caller */ + siglongjmp(to->env, action); +-- +1.8.3.1 + diff --git a/0054-block-io-clear-BDRV_BLOCK_RECURSE-flag-after-recursi.patch b/0054-block-io-clear-BDRV_BLOCK_RECURSE-flag-after-recursi.patch new file mode 100644 index 0000000000000000000000000000000000000000..35dba83db3e1c83a625929bfdf09a53e486d9b36 --- /dev/null +++ b/0054-block-io-clear-BDRV_BLOCK_RECURSE-flag-after-recursi.patch @@ -0,0 +1,109 @@ +From 99dd4a1563022338229791df41b42e320a38581b Mon Sep 17 00:00:00 2001 +From: Fiona Ebner +Date: Tue, 16 Jan 2024 16:48:39 +0100 +Subject: [PATCH 059/293] block/io: clear BDRV_BLOCK_RECURSE flag after + recursing in bdrv_co_block_status + +Using fleecing backup like in [0] on a qcow2 image (with metadata +preallocation) can lead to the following assertion failure: + +> bdrv_co_do_block_status: Assertion `!(ret & BDRV_BLOCK_ZERO)' failed. + +In the reproducer [0], it happens because the BDRV_BLOCK_RECURSE flag +will be set by the qcow2 driver, so the caller will recursively check +the file child. Then the BDRV_BLOCK_ZERO set too. Later up the call +chain, in bdrv_co_do_block_status() for the snapshot-access driver, +the assertion failure will happen, because both flags are set. + +To fix it, clear the recurse flag after the recursive check was done. + +In detail: + +> #0 qcow2_co_block_status + +Returns 0x45 = BDRV_BLOCK_RECURSE | BDRV_BLOCK_DATA | +BDRV_BLOCK_OFFSET_VALID. + +> #1 bdrv_co_do_block_status + +Because of the data flag, bdrv_co_do_block_status() will now also set +BDRV_BLOCK_ALLOCATED. Because of the recurse flag, +bdrv_co_do_block_status() for the bdrv_file child will be called, +which returns 0x16 = BDRV_BLOCK_ALLOCATED | BDRV_BLOCK_OFFSET_VALID | +BDRV_BLOCK_ZERO. Now the return value inherits the zero flag. + +Returns 0x57 = BDRV_BLOCK_RECURSE | BDRV_BLOCK_DATA | +BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_ALLOCATED | BDRV_BLOCK_ZERO. + +> #2 bdrv_co_common_block_status_above +> #3 bdrv_co_block_status_above +> #4 bdrv_co_block_status +> #5 cbw_co_snapshot_block_status +> #6 bdrv_co_snapshot_block_status +> #7 snapshot_access_co_block_status +> #8 bdrv_co_do_block_status + +Return value is propagated all the way up to here, where the assertion +failure happens, because BDRV_BLOCK_RECURSE and BDRV_BLOCK_ZERO are +both set. + +> #9 bdrv_co_common_block_status_above +> #10 bdrv_co_block_status_above +> #11 block_copy_block_status +> #12 block_copy_dirty_clusters +> #13 block_copy_common +> #14 block_copy_async_co_entry +> #15 coroutine_trampoline + +[0]: + +> #!/bin/bash +> rm /tmp/disk.qcow2 +> ./qemu-img create /tmp/disk.qcow2 -o preallocation=metadata -f qcow2 1G +> ./qemu-img create /tmp/fleecing.qcow2 -f qcow2 1G +> ./qemu-img create /tmp/backup.qcow2 -f qcow2 1G +> ./qemu-system-x86_64 --qmp stdio \ +> --blockdev qcow2,node-name=node0,file.driver=file,file.filename=/tmp/disk.qcow2 \ +> --blockdev qcow2,node-name=node1,file.driver=file,file.filename=/tmp/fleecing.qcow2 \ +> --blockdev qcow2,node-name=node2,file.driver=file,file.filename=/tmp/backup.qcow2 \ +> < {"execute": "qmp_capabilities"} +> {"execute": "blockdev-add", "arguments": { "driver": "copy-before-write", "file": "node0", "target": "node1", "node-name": "node3" } } +> {"execute": "blockdev-add", "arguments": { "driver": "snapshot-access", "file": "node3", "node-name": "snap0" } } +> {"execute": "blockdev-backup", "arguments": { "device": "snap0", "target": "node1", "sync": "full", "job-id": "backup0" } } +> EOF + +Signed-off-by: Fiona Ebner +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20240116154839.401030-1-f.ebner@proxmox.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 8a9be7992426c8920d4178e7dca59306a18c7a3a) +Signed-off-by: Michael Tokarev +--- + block/io.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/block/io.c b/block/io.c +index 7e62fab..d202987 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -2619,6 +2619,16 @@ bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero, + ret |= (ret2 & BDRV_BLOCK_ZERO); + } + } ++ ++ /* ++ * Now that the recursive search was done, clear the flag. Otherwise, ++ * with more complicated block graphs like snapshot-access -> ++ * copy-before-write -> qcow2, where the return value will be propagated ++ * further up to a parent bdrv_co_do_block_status() call, both the ++ * BDRV_BLOCK_RECURSE and BDRV_BLOCK_ZERO flags would be set, which is ++ * not allowed. ++ */ ++ ret &= ~BDRV_BLOCK_RECURSE; + } + + out: +-- +1.8.3.1 + diff --git a/0055-linux-user-Fixed-cpu-restore-with-pc-0-on-SIGBUS.patch b/0055-linux-user-Fixed-cpu-restore-with-pc-0-on-SIGBUS.patch new file mode 100644 index 0000000000000000000000000000000000000000..26f079a9e4418c8c1a92311cc7435a428eda424d --- /dev/null +++ b/0055-linux-user-Fixed-cpu-restore-with-pc-0-on-SIGBUS.patch @@ -0,0 +1,54 @@ +From 8bdd3abcf1c989ebe4428190e5789dfbbdf6c6ca Mon Sep 17 00:00:00 2001 +From: Robbin Ehn +Date: Fri, 12 Jan 2024 21:57:22 +0100 +Subject: [PATCH 060/293] linux-user: Fixed cpu restore with pc 0 on SIGBUS + +Commit f4e1168198 (linux-user: Split out host_sig{segv,bus}_handler) +introduced a bug, when returning from host_sigbus_handler the PC is +never set. Thus cpu_loop_exit_restore is called with a zero PC and +we immediate get a SIGSEGV. + +Signed-off-by: Robbin Ehn +Fixes: f4e1168198 ("linux-user: Split out host_sig{segv,bus}_handler") +Reviewed-by: Palmer Dabbelt +Message-Id: <33f27425878fb529b9e39ef22c303f6e0d90525f.camel@rivosinc.com> +Signed-off-by: Richard Henderson +(cherry picked from commit 6d913158b5023ac948b8fd649d77fc86e28072f6) +Signed-off-by: Michael Tokarev +--- + linux-user/signal.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/linux-user/signal.c b/linux-user/signal.c +index b35d1e5..c9527ad 100644 +--- a/linux-user/signal.c ++++ b/linux-user/signal.c +@@ -925,7 +925,7 @@ static void host_sigsegv_handler(CPUState *cpu, siginfo_t *info, + cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc); + } + +-static void host_sigbus_handler(CPUState *cpu, siginfo_t *info, ++static uintptr_t host_sigbus_handler(CPUState *cpu, siginfo_t *info, + host_sigcontext *uc) + { + uintptr_t pc = host_signal_pc(uc); +@@ -947,6 +947,7 @@ static void host_sigbus_handler(CPUState *cpu, siginfo_t *info, + sigprocmask(SIG_SETMASK, host_signal_mask(uc), NULL); + cpu_loop_exit_sigbus(cpu, guest_addr, access_type, pc); + } ++ return pc; + } + + static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) +@@ -974,7 +975,7 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) + host_sigsegv_handler(cpu, info, uc); + return; + case SIGBUS: +- host_sigbus_handler(cpu, info, uc); ++ pc = host_sigbus_handler(cpu, info, uc); + sync_sig = true; + break; + case SIGILL: +-- +1.8.3.1 + diff --git a/0056-tcg-arm-Fix-SIGILL-in-tcg_out_qemu_st_direct.patch b/0056-tcg-arm-Fix-SIGILL-in-tcg_out_qemu_st_direct.patch new file mode 100644 index 0000000000000000000000000000000000000000..0d621e669b50ab0fcbad9df4a9590917c5107857 --- /dev/null +++ b/0056-tcg-arm-Fix-SIGILL-in-tcg_out_qemu_st_direct.patch @@ -0,0 +1,37 @@ +From 6f6492ab070f10843c881690cacc3bf2e051f9e5 Mon Sep 17 00:00:00 2001 +From: Joseph Burt +Date: Sun, 21 Jan 2024 21:14:39 +0000 +Subject: [PATCH 062/293] tcg/arm: Fix SIGILL in tcg_out_qemu_st_direct + +When tcg_out_qemu_st_{index,direct} were merged, the direct case for +MO_64 was omitted, causing qemu_st_i64 to be encoded as 0xffffffff due +to underflow when adding h.base and h.index. + +Fixes: 1df6d611bdc2 ("tcg/arm: Introduce HostAddress") +Signed-off-by: Joseph Burt +Message-Id: <20240121211439.100829-1-caseorum@gmail.com> +Reviewed-by: Richard Henderson +Signed-off-by: Richard Henderson +(cherry picked from commit 9f6523e8e4689cafdbed7c10b7cf7c775b5a607b) +Signed-off-by: Michael Tokarev +--- + tcg/arm/tcg-target.c.inc | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc +index fc78566..a9aa8aa 100644 +--- a/tcg/arm/tcg-target.c.inc ++++ b/tcg/arm/tcg-target.c.inc +@@ -1662,6 +1662,9 @@ static void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg datalo, + } else { + tcg_out_strd_r(s, h.cond, datalo, h.base, h.index); + } ++ } else if (h.index < 0) { ++ tcg_out_st32_12(s, h.cond, datalo, h.base, 0); ++ tcg_out_st32_12(s, h.cond, datahi, h.base, 4); + } else if (h.index_scratch) { + tcg_out_st32_rwb(s, h.cond, datalo, h.index, h.base); + tcg_out_st32_12(s, h.cond, datahi, h.index, 4); +-- +1.8.3.1 + diff --git a/0057-virtio-net-correctly-copy-vnet-header-when-flushing-.patch b/0057-virtio-net-correctly-copy-vnet-header-when-flushing-.patch new file mode 100644 index 0000000000000000000000000000000000000000..5657b5acf3cda24d37f1f14e6a84eb16eee79140 --- /dev/null +++ b/0057-virtio-net-correctly-copy-vnet-header-when-flushing-.patch @@ -0,0 +1,74 @@ +From 939a09575fff7048446e36ce438fa7be6e251d41 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Tue, 2 Jan 2024 11:29:01 +0800 +Subject: [PATCH 063/293] virtio-net: correctly copy vnet header when flushing + TX + +When HASH_REPORT is negotiated, the guest_hdr_len might be larger than +the size of the mergeable rx buffer header. Using +virtio_net_hdr_mrg_rxbuf during the header swap might lead a stack +overflow in this case. Fixing this by using virtio_net_hdr_v1_hash +instead. + +Reported-by: Xiao Lei +Cc: Yuri Benditovich +Cc: qemu-stable@nongnu.org +Cc: Mauro Matteo Cascella +Fixes: CVE-2023-6693 +Fixes: e22f0603fb2f ("virtio-net: reference implementation of hash report") +Reviewed-by: Michael Tokarev +Signed-off-by: Jason Wang +(cherry picked from commit 2220e8189fb94068dbad333228659fbac819abb0) +Signed-off-by: Michael Tokarev +--- + hw/net/virtio-net.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 80c56f0..73024ba 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -674,6 +674,11 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs, + + n->mergeable_rx_bufs = mergeable_rx_bufs; + ++ /* ++ * Note: when extending the vnet header, please make sure to ++ * change the vnet header copying logic in virtio_net_flush_tx() ++ * as well. ++ */ + if (version_1) { + n->guest_hdr_len = hash_report ? + sizeof(struct virtio_net_hdr_v1_hash) : +@@ -2693,7 +2698,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) + ssize_t ret; + unsigned int out_num; + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg; +- struct virtio_net_hdr_mrg_rxbuf mhdr; ++ struct virtio_net_hdr_v1_hash vhdr; + + elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement)); + if (!elem) { +@@ -2710,7 +2715,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) + } + + if (n->has_vnet_hdr) { +- if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) < ++ if (iov_to_buf(out_sg, out_num, 0, &vhdr, n->guest_hdr_len) < + n->guest_hdr_len) { + virtio_error(vdev, "virtio-net header incorrect"); + virtqueue_detach_element(q->tx_vq, elem, 0); +@@ -2718,8 +2723,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) + return -EINVAL; + } + if (n->needs_vnet_hdr_swap) { +- virtio_net_hdr_swap(vdev, (void *) &mhdr); +- sg2[0].iov_base = &mhdr; ++ virtio_net_hdr_swap(vdev, (void *) &vhdr); ++ sg2[0].iov_base = &vhdr; + sg2[0].iov_len = n->guest_hdr_len; + out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1, + out_sg, out_num, +-- +1.8.3.1 + diff --git a/0058-block-blklogwrites-Fix-a-bug-when-logging-write-zero.patch b/0058-block-blklogwrites-Fix-a-bug-when-logging-write-zero.patch new file mode 100644 index 0000000000000000000000000000000000000000..bf511a674112fd80364c4e2267049309bba5be07 --- /dev/null +++ b/0058-block-blklogwrites-Fix-a-bug-when-logging-write-zero.patch @@ -0,0 +1,107 @@ +From cf70966523fd6c13ce1fff764eac0e1bfdf785a3 Mon Sep 17 00:00:00 2001 +From: Ari Sundholm +Date: Tue, 9 Jan 2024 20:46:46 +0200 +Subject: [PATCH 064/293] block/blklogwrites: Fix a bug when logging "write + zeroes" operations. + +There is a bug in the blklogwrites driver pertaining to logging "write +zeroes" operations, causing log corruption. This can be easily observed +by setting detect-zeroes to something other than "off" for the driver. + +The issue is caused by a concurrency bug pertaining to the fact that +"write zeroes" operations have to be logged in two parts: first the log +entry metadata, then the zeroed-out region. While the log entry +metadata is being written by bdrv_co_pwritev(), another operation may +begin in the meanwhile and modify the state of the blklogwrites driver. +This is as intended by the coroutine-driven I/O model in QEMU, of +course. + +Unfortunately, this specific scenario is mishandled. A short example: + 1. Initially, in the current operation (#1), the current log sector +number in the driver state is only incremented by the number of sectors +taken by the log entry metadata, after which the log entry metadata is +written. The current operation yields. + 2. Another operation (#2) may start while the log entry metadata is +being written. It uses the current log position as the start offset for +its log entry. This is in the sector right after the operation #1 log +entry metadata, which is bad! + 3. After bdrv_co_pwritev() returns (#1), the current log sector +number is reread from the driver state in order to find out the start +offset for bdrv_co_pwrite_zeroes(). This is an obvious blunder, as the +offset will be the sector right after the (misplaced) operation #2 log +entry, which means that the zeroed-out region begins at the wrong +offset. + 4. As a result of the above, the log is corrupt. + +Fix this by only reading the driver metadata once, computing the +offsets and sizes in one go (including the optional zeroed-out region) +and setting the log sector number to the appropriate value for the next +operation in line. + +Signed-off-by: Ari Sundholm +Cc: qemu-stable@nongnu.org +Message-ID: <20240109184646.1128475-1-megari@gmx.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit a9c8ea95470c27a8a02062b67f9fa6940e828ab6) +Signed-off-by: Michael Tokarev +--- + block/blklogwrites.c | 35 ++++++++++++++++++++++++++--------- + 1 file changed, 26 insertions(+), 9 deletions(-) + +diff --git a/block/blklogwrites.c b/block/blklogwrites.c +index 3678f6c..84e03f3 100644 +--- a/block/blklogwrites.c ++++ b/block/blklogwrites.c +@@ -328,22 +328,39 @@ static void coroutine_fn GRAPH_RDLOCK + blk_log_writes_co_do_log(BlkLogWritesLogReq *lr) + { + BDRVBlkLogWritesState *s = lr->bs->opaque; +- uint64_t cur_log_offset = s->cur_log_sector << s->sectorbits; + +- s->nr_entries++; +- s->cur_log_sector += +- ROUND_UP(lr->qiov->size, s->sectorsize) >> s->sectorbits; ++ /* ++ * Determine the offsets and sizes of different parts of the entry, and ++ * update the state of the driver. ++ * ++ * This needs to be done in one go, before any actual I/O is done, as the ++ * log entry may have to be written in two parts, and the state of the ++ * driver may be modified by other driver operations while waiting for the ++ * I/O to complete. ++ */ ++ const uint64_t entry_start_sector = s->cur_log_sector; ++ const uint64_t entry_offset = entry_start_sector << s->sectorbits; ++ const uint64_t qiov_aligned_size = ROUND_UP(lr->qiov->size, s->sectorsize); ++ const uint64_t entry_aligned_size = qiov_aligned_size + ++ ROUND_UP(lr->zero_size, s->sectorsize); ++ const uint64_t entry_nr_sectors = entry_aligned_size >> s->sectorbits; + +- lr->log_ret = bdrv_co_pwritev(s->log_file, cur_log_offset, lr->qiov->size, ++ s->nr_entries++; ++ s->cur_log_sector += entry_nr_sectors; ++ ++ /* ++ * Write the log entry. Note that if this is a "write zeroes" operation, ++ * only the entry header is written here, with the zeroing being done ++ * separately below. ++ */ ++ lr->log_ret = bdrv_co_pwritev(s->log_file, entry_offset, lr->qiov->size, + lr->qiov, 0); + + /* Logging for the "write zeroes" operation */ + if (lr->log_ret == 0 && lr->zero_size) { +- cur_log_offset = s->cur_log_sector << s->sectorbits; +- s->cur_log_sector += +- ROUND_UP(lr->zero_size, s->sectorsize) >> s->sectorbits; ++ const uint64_t zeroes_offset = entry_offset + qiov_aligned_size; + +- lr->log_ret = bdrv_co_pwrite_zeroes(s->log_file, cur_log_offset, ++ lr->log_ret = bdrv_co_pwrite_zeroes(s->log_file, zeroes_offset, + lr->zero_size, 0); + } + +-- +1.8.3.1 + diff --git a/0059-iotests-add-filter_qmp_generated_node_ids.patch b/0059-iotests-add-filter_qmp_generated_node_ids.patch new file mode 100644 index 0000000000000000000000000000000000000000..0d28cedcac0e366255145ab092d84b398920a3d9 --- /dev/null +++ b/0059-iotests-add-filter_qmp_generated_node_ids.patch @@ -0,0 +1,42 @@ +From d7a64c4517c2b59429ac7edea7c2b52e4806e135 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Thu, 18 Jan 2024 09:48:21 -0500 +Subject: [PATCH 065/293] iotests: add filter_qmp_generated_node_ids() + +Add a filter function for QMP responses that contain QEMU's +automatically generated node ids. The ids change between runs and must +be masked in the reference output. + +The next commit will use this new function. + +Signed-off-by: Stefan Hajnoczi +Message-ID: <20240118144823.1497953-2-stefanha@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit da62b507a20510d819bcfbe8f5e573409b954006) +Signed-off-by: Michael Tokarev +--- + tests/qemu-iotests/iotests.py | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index e5c5798..ea48af4 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -651,6 +651,13 @@ def _filter(_key, value): + def filter_generated_node_ids(msg): + return re.sub("#block[0-9]+", "NODE_NAME", msg) + ++def filter_qmp_generated_node_ids(qmsg): ++ def _filter(_key, value): ++ if is_str(value): ++ return filter_generated_node_ids(value) ++ return value ++ return filter_qmp(qmsg, _filter) ++ + def filter_img_info(output: str, filename: str, + drop_child_info: bool = True) -> str: + lines = [] +-- +1.8.3.1 + diff --git a/0060-iotests-port-141-to-Python-for-reliable-QMP-testing.patch b/0060-iotests-port-141-to-Python-for-reliable-QMP-testing.patch new file mode 100644 index 0000000000000000000000000000000000000000..244013349a184f8eda1b2020f71d4cf766863b23 --- /dev/null +++ b/0060-iotests-port-141-to-Python-for-reliable-QMP-testing.patch @@ -0,0 +1,585 @@ +From 823892d19f6b79dc44ac1a885a9ceed0bd0965e7 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Thu, 18 Jan 2024 09:48:22 -0500 +Subject: [PATCH 066/293] iotests: port 141 to Python for reliable QMP testing + +The common.qemu bash functions allow tests to interact with the QMP +monitor of a QEMU process. I spent two days trying to update 141 when +the order of the test output changed, but found it would still fail +occassionally because printf() and QMP events race with synchronous QMP +communication. + +I gave up and ported 141 to the existing Python API for QMP tests. The +Python API is less affected by the order in which QEMU prints output +because it does not print all QMP traffic by default. + +The next commit changes the order in which QMP messages are received. +Make 141 reliable first. + +Cc: Hanna Czenczek +Signed-off-by: Stefan Hajnoczi +Message-ID: <20240118144823.1497953-3-stefanha@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 9ee2dd4c22a3639c5462b3fc20df60c005c3de64) +Signed-off-by: Michael Tokarev +--- + tests/qemu-iotests/141 | 307 +++++++++++++++++++-------------------------- + tests/qemu-iotests/141.out | 200 +++++++---------------------- + 2 files changed, 176 insertions(+), 331 deletions(-) + +diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141 +index a37030e..a7d3985 100755 +--- a/tests/qemu-iotests/141 ++++ b/tests/qemu-iotests/141 +@@ -1,9 +1,12 @@ +-#!/usr/bin/env bash ++#!/usr/bin/env python3 + # group: rw auto quick + # + # Test case for ejecting BDSs with block jobs still running on them + # +-# Copyright (C) 2016 Red Hat, Inc. ++# Originally written in bash by Hanna Czenczek, ported to Python by Stefan ++# Hajnoczi. ++# ++# Copyright Red Hat + # + # This program is free software; you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -19,177 +22,129 @@ + # along with this program. If not, see . + # + +-# creator +-owner=hreitz@redhat.com +- +-seq="$(basename $0)" +-echo "QA output created by $seq" +- +-status=1 # failure is the default! +- +-_cleanup() +-{ +- _cleanup_qemu +- _cleanup_test_img +- for img in "$TEST_DIR"/{b,m,o}.$IMGFMT; do +- _rm_test_img "$img" +- done +-} +-trap "_cleanup; exit \$status" 0 1 2 3 15 +- +-# get standard environment, filters and checks +-. ./common.rc +-. ./common.filter +-. ./common.qemu +- +-# Needs backing file and backing format support +-_supported_fmt qcow2 qed +-_supported_proto file +-_supported_os Linux +- +- +-test_blockjob() +-{ +- _send_qemu_cmd $QEMU_HANDLE \ +- "{'execute': 'blockdev-add', +- 'arguments': { +- 'node-name': 'drv0', +- 'driver': '$IMGFMT', +- 'file': { +- 'driver': 'file', +- 'filename': '$TEST_IMG' +- }}}" \ +- 'return' +- +- # If "$2" is an event, we may or may not see it before the +- # {"return": {}}. Therefore, filter the {"return": {}} out both +- # here and in the next command. (Naturally, if we do not see it +- # here, we will see it before the next command can be executed, +- # so it will appear in the next _send_qemu_cmd's output.) +- _send_qemu_cmd $QEMU_HANDLE \ +- "$1" \ +- "$2" \ +- | _filter_img_create | _filter_qmp_empty_return +- +- # We want this to return an error because the block job is still running +- _send_qemu_cmd $QEMU_HANDLE \ +- "{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}}" \ +- 'error' | _filter_generated_node_ids | _filter_qmp_empty_return +- +- _send_qemu_cmd $QEMU_HANDLE \ +- "{'execute': 'block-job-cancel', +- 'arguments': {'device': 'job0'}}" \ +- "$3" +- +- _send_qemu_cmd $QEMU_HANDLE \ +- "{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}}" \ +- 'return' +-} +- +- +-TEST_IMG="$TEST_DIR/b.$IMGFMT" _make_test_img 1M +-TEST_IMG="$TEST_DIR/m.$IMGFMT" _make_test_img -b "$TEST_DIR/b.$IMGFMT" -F $IMGFMT 1M +-_make_test_img -b "$TEST_DIR/m.$IMGFMT" 1M -F $IMGFMT +- +-_launch_qemu -nodefaults +- +-_send_qemu_cmd $QEMU_HANDLE \ +- "{'execute': 'qmp_capabilities'}" \ +- 'return' +- +-echo +-echo '=== Testing drive-backup ===' +-echo +- +-# drive-backup will not send BLOCK_JOB_READY by itself, and cancelling the job +-# will consequently result in BLOCK_JOB_CANCELLED being emitted. +- +-test_blockjob \ +- "{'execute': 'drive-backup', +- 'arguments': {'job-id': 'job0', +- 'device': 'drv0', +- 'target': '$TEST_DIR/o.$IMGFMT', +- 'format': '$IMGFMT', +- 'sync': 'none'}}" \ +- 'return' \ +- '"status": "null"' +- +-echo +-echo '=== Testing drive-mirror ===' +-echo +- +-# drive-mirror will send BLOCK_JOB_READY basically immediately, and cancelling +-# the job will consequently result in BLOCK_JOB_COMPLETED being emitted. +- +-test_blockjob \ +- "{'execute': 'drive-mirror', +- 'arguments': {'job-id': 'job0', +- 'device': 'drv0', +- 'target': '$TEST_DIR/o.$IMGFMT', +- 'format': '$IMGFMT', +- 'sync': 'none'}}" \ +- 'BLOCK_JOB_READY' \ +- '"status": "null"' +- +-echo +-echo '=== Testing active block-commit ===' +-echo +- +-# An active block-commit will send BLOCK_JOB_READY basically immediately, and +-# cancelling the job will consequently result in BLOCK_JOB_COMPLETED being +-# emitted. +- +-test_blockjob \ +- "{'execute': 'block-commit', +- 'arguments': {'job-id': 'job0', 'device': 'drv0'}}" \ +- 'BLOCK_JOB_READY' \ +- '"status": "null"' +- +-echo +-echo '=== Testing non-active block-commit ===' +-echo +- +-# Give block-commit something to work on, otherwise it would be done +-# immediately, send a BLOCK_JOB_COMPLETED and ejecting the BDS would work just +-# fine without the block job still running. +- +-$QEMU_IO -c 'write 0 1M' "$TEST_DIR/m.$IMGFMT" | _filter_qemu_io +- +-test_blockjob \ +- "{'execute': 'block-commit', +- 'arguments': {'job-id': 'job0', +- 'device': 'drv0', +- 'top': '$TEST_DIR/m.$IMGFMT', +- 'speed': 1}}" \ +- 'return' \ +- '"status": "null"' +- +-echo +-echo '=== Testing block-stream ===' +-echo +- +-# Give block-stream something to work on, otherwise it would be done +-# immediately, send a BLOCK_JOB_COMPLETED and ejecting the BDS would work just +-# fine without the block job still running. +- +-$QEMU_IO -c 'write 0 1M' "$TEST_DIR/b.$IMGFMT" | _filter_qemu_io +- +-# With some data to stream (and @speed set to 1), block-stream will not complete +-# until we send the block-job-cancel command. +- +-test_blockjob \ +- "{'execute': 'block-stream', +- 'arguments': {'job-id': 'job0', +- 'device': 'drv0', +- 'speed': 1}}" \ +- 'return' \ +- '"status": "null"' +- +-_cleanup_qemu +- +-# success, all done +-echo "*** done" +-rm -f $seq.full +-status=0 ++import iotests ++ ++# Common filters to mask values that vary in the test output ++QMP_FILTERS = [iotests.filter_qmp_testfiles, \ ++ iotests.filter_qmp_imgfmt] ++ ++ ++class TestCase: ++ def __init__(self, name, vm, image_path, cancel_event): ++ self.name = name ++ self.vm = vm ++ self.image_path = image_path ++ self.cancel_event = cancel_event ++ ++ def __enter__(self): ++ iotests.log(f'=== Testing {self.name} ===') ++ self.vm.qmp_log('blockdev-add', \ ++ node_name='drv0', \ ++ driver=iotests.imgfmt, \ ++ file={'driver': 'file', 'filename': self.image_path}, \ ++ filters=QMP_FILTERS) ++ ++ def __exit__(self, *exc_details): ++ # This is expected to fail because the job still exists ++ self.vm.qmp_log('blockdev-del', node_name='drv0', \ ++ filters=[iotests.filter_qmp_generated_node_ids]) ++ ++ self.vm.qmp_log('block-job-cancel', device='job0') ++ event = self.vm.event_wait(self.cancel_event) ++ iotests.log(event, filters=[iotests.filter_qmp_event]) ++ ++ # This time it succeeds ++ self.vm.qmp_log('blockdev-del', node_name='drv0') ++ ++ # Separate test cases in output ++ iotests.log('') ++ ++ ++def main() -> None: ++ with iotests.FilePath('bottom', 'middle', 'top', 'target') as \ ++ (bottom_path, middle_path, top_path, target_path), \ ++ iotests.VM() as vm: ++ ++ iotests.log('Creating bottom <- middle <- top backing file chain...') ++ IMAGE_SIZE='1M' ++ iotests.qemu_img_create('-f', iotests.imgfmt, bottom_path, IMAGE_SIZE) ++ iotests.qemu_img_create('-f', iotests.imgfmt, \ ++ '-F', iotests.imgfmt, \ ++ '-b', bottom_path, \ ++ middle_path, \ ++ IMAGE_SIZE) ++ iotests.qemu_img_create('-f', iotests.imgfmt, \ ++ '-F', iotests.imgfmt, \ ++ '-b', middle_path, \ ++ top_path, \ ++ IMAGE_SIZE) ++ ++ iotests.log('Starting VM...') ++ vm.add_args('-nodefaults') ++ vm.launch() ++ ++ # drive-backup will not send BLOCK_JOB_READY by itself, and cancelling ++ # the job will consequently result in BLOCK_JOB_CANCELLED being ++ # emitted. ++ with TestCase('drive-backup', vm, top_path, 'BLOCK_JOB_CANCELLED'): ++ vm.qmp_log('drive-backup', \ ++ job_id='job0', \ ++ device='drv0', \ ++ target=target_path, \ ++ format=iotests.imgfmt, \ ++ sync='none', \ ++ filters=QMP_FILTERS) ++ ++ # drive-mirror will send BLOCK_JOB_READY basically immediately, and ++ # cancelling the job will consequently result in BLOCK_JOB_COMPLETED ++ # being emitted. ++ with TestCase('drive-mirror', vm, top_path, 'BLOCK_JOB_COMPLETED'): ++ vm.qmp_log('drive-mirror', \ ++ job_id='job0', \ ++ device='drv0', \ ++ target=target_path, \ ++ format=iotests.imgfmt, \ ++ sync='none', \ ++ filters=QMP_FILTERS) ++ event = vm.event_wait('BLOCK_JOB_READY') ++ assert event is not None # silence mypy ++ iotests.log(event, filters=[iotests.filter_qmp_event]) ++ ++ # An active block-commit will send BLOCK_JOB_READY basically ++ # immediately, and cancelling the job will consequently result in ++ # BLOCK_JOB_COMPLETED being emitted. ++ with TestCase('active block-commit', vm, top_path, \ ++ 'BLOCK_JOB_COMPLETED'): ++ vm.qmp_log('block-commit', \ ++ job_id='job0', \ ++ device='drv0') ++ event = vm.event_wait('BLOCK_JOB_READY') ++ assert event is not None # silence mypy ++ iotests.log(event, filters=[iotests.filter_qmp_event]) ++ ++ # Give block-commit something to work on, otherwise it would be done ++ # immediately, send a BLOCK_JOB_COMPLETED and ejecting the BDS would ++ # work just fine without the block job still running. ++ iotests.qemu_io(middle_path, '-c', f'write 0 {IMAGE_SIZE}') ++ with TestCase('non-active block-commit', vm, top_path, \ ++ 'BLOCK_JOB_CANCELLED'): ++ vm.qmp_log('block-commit', \ ++ job_id='job0', \ ++ device='drv0', \ ++ top=middle_path, \ ++ speed=1, \ ++ filters=[iotests.filter_qmp_testfiles]) ++ ++ # Give block-stream something to work on, otherwise it would be done ++ # immediately, send a BLOCK_JOB_COMPLETED and ejecting the BDS would ++ # work just fine without the block job still running. ++ iotests.qemu_io(bottom_path, '-c', f'write 0 {IMAGE_SIZE}') ++ with TestCase('block-stream', vm, top_path, 'BLOCK_JOB_CANCELLED'): ++ vm.qmp_log('block-stream', \ ++ job_id='job0', \ ++ device='drv0', \ ++ speed=1) ++ ++if __name__ == '__main__': ++ iotests.script_main(main, supported_fmts=['qcow2', 'qed'], ++ supported_protocols=['file']) +diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out +index 63203d9..91b7ba5 100644 +--- a/tests/qemu-iotests/141.out ++++ b/tests/qemu-iotests/141.out +@@ -1,179 +1,69 @@ +-QA output created by 141 +-Formatting 'TEST_DIR/b.IMGFMT', fmt=IMGFMT size=1048576 +-Formatting 'TEST_DIR/m.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/b.IMGFMT backing_fmt=IMGFMT +-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.IMGFMT backing_fmt=IMGFMT +-{'execute': 'qmp_capabilities'} +-{"return": {}} +- ++Creating bottom <- middle <- top backing file chain... ++Starting VM... + === Testing drive-backup === +- +-{'execute': 'blockdev-add', +- 'arguments': { +- 'node-name': 'drv0', +- 'driver': 'IMGFMT', +- 'file': { +- 'driver': 'file', +- 'filename': 'TEST_DIR/t.IMGFMT' +- }}} +-{"return": {}} +-{'execute': 'drive-backup', +-'arguments': {'job-id': 'job0', +-'device': 'drv0', +-'target': 'TEST_DIR/o.IMGFMT', +-'format': 'IMGFMT', +-'sync': 'none'}} +-Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} +-{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}} ++{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top"}, "node-name": "drv0"}} ++{"return": {}} ++{"execute": "drive-backup", "arguments": {"device": "drv0", "format": "IMGFMT", "job-id": "job0", "sync": "none", "target": "TEST_DIR/PID-target"}} ++{"return": {}} ++{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}} + {"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}} +-{'execute': 'block-job-cancel', +- 'arguments': {'device': 'job0'}} ++{"execute": "block-job-cancel", "arguments": {"device": "job0"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} +-{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}} ++{"data": {"device": "job0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}} + {"return": {}} + + === Testing drive-mirror === +- +-{'execute': 'blockdev-add', +- 'arguments': { +- 'node-name': 'drv0', +- 'driver': 'IMGFMT', +- 'file': { +- 'driver': 'file', +- 'filename': 'TEST_DIR/t.IMGFMT' +- }}} +-{"return": {}} +-{'execute': 'drive-mirror', +-'arguments': {'job-id': 'job0', +-'device': 'drv0', +-'target': 'TEST_DIR/o.IMGFMT', +-'format': 'IMGFMT', +-'sync': 'none'}} +-Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} +-{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}} ++{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top"}, "node-name": "drv0"}} ++{"return": {}} ++{"execute": "drive-mirror", "arguments": {"device": "drv0", "format": "IMGFMT", "job-id": "job0", "sync": "none", "target": "TEST_DIR/PID-target"}} ++{"return": {}} ++{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}} + {"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: mirror"}} +-{'execute': 'block-job-cancel', +- 'arguments': {'device': 'job0'}} ++{"execute": "block-job-cancel", "arguments": {"device": "job0"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} +-{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}} ++{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}} + {"return": {}} + + === Testing active block-commit === +- +-{'execute': 'blockdev-add', +- 'arguments': { +- 'node-name': 'drv0', +- 'driver': 'IMGFMT', +- 'file': { +- 'driver': 'file', +- 'filename': 'TEST_DIR/t.IMGFMT' +- }}} +-{"return": {}} +-{'execute': 'block-commit', +-'arguments': {'job-id': 'job0', 'device': 'drv0'}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} +-{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}} ++{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top"}, "node-name": "drv0"}} ++{"return": {}} ++{"execute": "block-commit", "arguments": {"device": "drv0", "job-id": "job0"}} ++{"return": {}} ++{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}} + {"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}} +-{'execute': 'block-job-cancel', +- 'arguments': {'device': 'job0'}} ++{"execute": "block-job-cancel", "arguments": {"device": "job0"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} +-{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}} ++{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}} + {"return": {}} + + === Testing non-active block-commit === +- +-wrote 1048576/1048576 bytes at offset 0 +-1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-{'execute': 'blockdev-add', +- 'arguments': { +- 'node-name': 'drv0', +- 'driver': 'IMGFMT', +- 'file': { +- 'driver': 'file', +- 'filename': 'TEST_DIR/t.IMGFMT' +- }}} +-{"return": {}} +-{'execute': 'block-commit', +-'arguments': {'job-id': 'job0', +-'device': 'drv0', +-'top': 'TEST_DIR/m.IMGFMT', +-'speed': 1}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} +-{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}} ++{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top"}, "node-name": "drv0"}} ++{"return": {}} ++{"execute": "block-commit", "arguments": {"device": "drv0", "job-id": "job0", "speed": 1, "top": "TEST_DIR/PID-middle"}} ++{"return": {}} ++{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}} + {"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}} +-{'execute': 'block-job-cancel', +- 'arguments': {'device': 'job0'}} ++{"execute": "block-job-cancel", "arguments": {"device": "job0"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} +-{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}} ++{"data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}} + {"return": {}} + + === Testing block-stream === +- +-wrote 1048576/1048576 bytes at offset 0 +-1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-{'execute': 'blockdev-add', +- 'arguments': { +- 'node-name': 'drv0', +- 'driver': 'IMGFMT', +- 'file': { +- 'driver': 'file', +- 'filename': 'TEST_DIR/t.IMGFMT' +- }}} +-{"return": {}} +-{'execute': 'block-stream', +-'arguments': {'job-id': 'job0', +-'device': 'drv0', +-'speed': 1}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} +-{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}} ++{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top"}, "node-name": "drv0"}} ++{"return": {}} ++{"execute": "block-stream", "arguments": {"device": "drv0", "job-id": "job0", "speed": 1}} ++{"return": {}} ++{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}} + {"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: stream"}} +-{'execute': 'block-job-cancel', +- 'arguments': {'device': 'job0'}} ++{"execute": "block-job-cancel", "arguments": {"device": "job0"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} +-{'execute': 'blockdev-del', +- 'arguments': {'node-name': 'drv0'}} ++{"data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}} + {"return": {}} +-*** done ++ +-- +1.8.3.1 + diff --git a/0061-monitor-only-run-coroutine-commands-in-qemu_aio_cont.patch b/0061-monitor-only-run-coroutine-commands-in-qemu_aio_cont.patch new file mode 100644 index 0000000000000000000000000000000000000000..0dbc32e10b9c71f764a55e9d37887403e42eb12e --- /dev/null +++ b/0061-monitor-only-run-coroutine-commands-in-qemu_aio_cont.patch @@ -0,0 +1,1623 @@ +From f389309d2937e66960dd371014a1971678fb4ce7 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Thu, 18 Jan 2024 09:48:23 -0500 +Subject: [PATCH 067/293] monitor: only run coroutine commands in + qemu_aio_context + +monitor_qmp_dispatcher_co() runs in the iohandler AioContext that is not +polled during nested event loops. The coroutine currently reschedules +itself in the main loop's qemu_aio_context AioContext, which is polled +during nested event loops. One known problem is that QMP device-add +calls drain_call_rcu(), which temporarily drops the BQL, leading to all +sorts of havoc like other vCPU threads re-entering device emulation code +while another vCPU thread is waiting in device emulation code with +aio_poll(). + +Paolo Bonzini suggested running non-coroutine QMP handlers in the +iohandler AioContext. This avoids trouble with nested event loops. His +original idea was to move coroutine rescheduling to +monitor_qmp_dispatch(), but I resorted to moving it to qmp_dispatch() +because we don't know if the QMP handler needs to run in coroutine +context in monitor_qmp_dispatch(). monitor_qmp_dispatch() would have +been nicer since it's associated with the monitor implementation and not +as general as qmp_dispatch(), which is also used by qemu-ga. + +A number of qemu-iotests need updated .out files because the order of +QMP events vs QMP responses has changed. + +Solves Issue #1933. + +Cc: qemu-stable@nongnu.org +Fixes: 7bed89958bfbf40df9ca681cefbdca63abdde39d ("device_core: use drain_call_rcu in in qmp_device_add") +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2215192 +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2214985 +Buglink: https://issues.redhat.com/browse/RHEL-17369 +Signed-off-by: Stefan Hajnoczi +Message-ID: <20240118144823.1497953-4-stefanha@redhat.com> +Reviewed-by: Kevin Wolf +Tested-by: Fiona Ebner +Signed-off-by: Kevin Wolf +(cherry picked from commit effd60c878176bcaf97fa7ce2b12d04bb8ead6f7) +Signed-off-by: Michael Tokarev +--- + monitor/qmp.c | 17 ------ + qapi/qmp-dispatch.c | 24 ++++++++- + tests/qemu-iotests/060.out | 4 +- + tests/qemu-iotests/071.out | 4 +- + tests/qemu-iotests/081.out | 16 +++--- + tests/qemu-iotests/087.out | 12 ++--- + tests/qemu-iotests/108.out | 2 +- + tests/qemu-iotests/109 | 4 +- + tests/qemu-iotests/109.out | 78 ++++++++++++--------------- + tests/qemu-iotests/117.out | 2 +- + tests/qemu-iotests/120.out | 2 +- + tests/qemu-iotests/127.out | 2 +- + tests/qemu-iotests/140.out | 2 +- + tests/qemu-iotests/143.out | 2 +- + tests/qemu-iotests/156.out | 2 +- + tests/qemu-iotests/176.out | 16 +++--- + tests/qemu-iotests/182.out | 2 +- + tests/qemu-iotests/183.out | 4 +- + tests/qemu-iotests/184.out | 32 +++++------ + tests/qemu-iotests/185 | 6 +-- + tests/qemu-iotests/185.out | 45 ++++++++++++++-- + tests/qemu-iotests/191.out | 16 +++--- + tests/qemu-iotests/195.out | 16 +++--- + tests/qemu-iotests/223.out | 12 ++--- + tests/qemu-iotests/227.out | 32 +++++------ + tests/qemu-iotests/247.out | 2 +- + tests/qemu-iotests/273.out | 8 +-- + tests/qemu-iotests/308 | 4 +- + tests/qemu-iotests/308.out | 4 +- + tests/qemu-iotests/tests/file-io-error | 5 +- + tests/qemu-iotests/tests/iothreads-resize.out | 2 +- + tests/qemu-iotests/tests/qsd-jobs.out | 4 +- + 32 files changed, 205 insertions(+), 178 deletions(-) + +diff --git a/monitor/qmp.c b/monitor/qmp.c +index 6eee450..a239945 100644 +--- a/monitor/qmp.c ++++ b/monitor/qmp.c +@@ -321,14 +321,6 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data) + qemu_coroutine_yield(); + } + +- /* +- * Move the coroutine from iohandler_ctx to qemu_aio_context for +- * executing the command handler so that it can make progress if it +- * involves an AIO_WAIT_WHILE(). +- */ +- aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co); +- qemu_coroutine_yield(); +- + /* Process request */ + if (req_obj->req) { + if (trace_event_get_state(TRACE_MONITOR_QMP_CMD_IN_BAND)) { +@@ -355,15 +347,6 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data) + } + + qmp_request_free(req_obj); +- +- /* +- * Yield and reschedule so the main loop stays responsive. +- * +- * Move back to iohandler_ctx so that nested event loops for +- * qemu_aio_context don't start new monitor commands. +- */ +- aio_co_schedule(iohandler_get_aio_context(), qmp_dispatcher_co); +- qemu_coroutine_yield(); + } + qatomic_set(&qmp_dispatcher_co, NULL); + } +diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c +index 555528b..176b549 100644 +--- a/qapi/qmp-dispatch.c ++++ b/qapi/qmp-dispatch.c +@@ -206,9 +206,31 @@ QDict *coroutine_mixed_fn qmp_dispatch(const QmpCommandList *cmds, QObject *requ + assert(!(oob && qemu_in_coroutine())); + assert(monitor_cur() == NULL); + if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) { ++ if (qemu_in_coroutine()) { ++ /* ++ * Move the coroutine from iohandler_ctx to qemu_aio_context for ++ * executing the command handler so that it can make progress if it ++ * involves an AIO_WAIT_WHILE(). ++ */ ++ aio_co_schedule(qemu_get_aio_context(), qemu_coroutine_self()); ++ qemu_coroutine_yield(); ++ } ++ + monitor_set_cur(qemu_coroutine_self(), cur_mon); + cmd->fn(args, &ret, &err); + monitor_set_cur(qemu_coroutine_self(), NULL); ++ ++ if (qemu_in_coroutine()) { ++ /* ++ * Yield and reschedule so the main loop stays responsive. ++ * ++ * Move back to iohandler_ctx so that nested event loops for ++ * qemu_aio_context don't start new monitor commands. ++ */ ++ aio_co_schedule(iohandler_get_aio_context(), ++ qemu_coroutine_self()); ++ qemu_coroutine_yield(); ++ } + } else { + /* + * Actual context doesn't match the one the command needs. +@@ -232,7 +254,7 @@ QDict *coroutine_mixed_fn qmp_dispatch(const QmpCommandList *cmds, QObject *requ + .errp = &err, + .co = qemu_coroutine_self(), + }; +- aio_bh_schedule_oneshot(qemu_get_aio_context(), do_qmp_dispatch_bh, ++ aio_bh_schedule_oneshot(iohandler_get_aio_context(), do_qmp_dispatch_bh, + &data); + qemu_coroutine_yield(); + } +diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out +index 329977d..a37bf44 100644 +--- a/tests/qemu-iotests/060.out ++++ b/tests/qemu-iotests/060.out +@@ -421,8 +421,8 @@ QMP_VERSION + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "none0", "msg": "Preventing invalid write on metadata (overlaps with refcount table)", "offset": 65536, "node-name": "drive", "fatal": true, "size": 65536}} + write failed: Input/output error + {"return": ""} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + === Testing incoming inactive corrupted image === + +@@ -432,8 +432,8 @@ QMP_VERSION + qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1 index: 0); further non-fatal corruption events will be suppressed + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a00 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}} + {"return": ""} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + corrupt: false + *** done +diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out +index bca0c02..a2923b0 100644 +--- a/tests/qemu-iotests/071.out ++++ b/tests/qemu-iotests/071.out +@@ -45,8 +45,8 @@ QMP_VERSION + {"return": {}} + read failed: Input/output error + {"return": ""} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + + === Testing blkverify on existing block device === +@@ -84,9 +84,9 @@ wrote 512/512 bytes at offset 0 + {"return": ""} + read failed: Input/output error + {"return": ""} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + QEMU_PROG: Failed to flush the L2 table cache: Input/output error + QEMU_PROG: Failed to flush the refcount block cache: Input/output error ++{"return": {}} + + *** done +diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out +index 615c083..aba85ea 100644 +--- a/tests/qemu-iotests/081.out ++++ b/tests/qemu-iotests/081.out +@@ -35,8 +35,8 @@ QMP_VERSION + read 10485760/10485760 bytes at offset 0 + 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": ""} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + + == using quorum rewrite corrupted mode == +@@ -67,8 +67,8 @@ QMP_VERSION + read 10485760/10485760 bytes at offset 0 + 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": ""} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + -- checking that the image has been corrected -- + read 10485760/10485760 bytes at offset 0 +@@ -106,8 +106,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + Testing: + QMP_VERSION +@@ -115,8 +115,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"error": {"class": "GenericError", "desc": "Cannot add a child to a quorum in blkverify mode"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + + == dynamically removing a child from a quorum == +@@ -125,31 +125,31 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + Testing: + QMP_VERSION + {"return": {}} + {"return": {}} + {"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + Testing: + QMP_VERSION + {"return": {}} + {"error": {"class": "GenericError", "desc": "blkverify=on can only be set if there are exactly two files and vote-threshold is 2"}} + {"error": {"class": "GenericError", "desc": "Cannot find device='drive0-quorum' nor node-name='drive0-quorum'"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + Testing: + QMP_VERSION + {"return": {}} + {"return": {}} + {"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + *** done +diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out +index e1c23a6..97b6d80 100644 +--- a/tests/qemu-iotests/087.out ++++ b/tests/qemu-iotests/087.out +@@ -7,8 +7,8 @@ Testing: + QMP_VERSION + {"return": {}} + {"error": {"class": "GenericError", "desc": "'node-name' must be specified for the root node"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + + === Duplicate ID === +@@ -18,8 +18,8 @@ QMP_VERSION + {"return": {}} + {"error": {"class": "GenericError", "desc": "node-name=disk is conflicting with a device id"}} + {"error": {"class": "GenericError", "desc": "Duplicate nodes with node-name='test-node'"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + + === aio=native without O_DIRECT === +@@ -28,8 +28,8 @@ Testing: + QMP_VERSION + {"return": {}} + {"error": {"class": "GenericError", "desc": "aio=native was specified, but it requires cache.direct=on, which was not specified."}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + + === Encrypted image QCow === +@@ -40,8 +40,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + + === Encrypted image LUKS === +@@ -52,8 +52,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + + === Missing driver === +@@ -63,7 +63,7 @@ Testing: -S + QMP_VERSION + {"return": {}} + {"error": {"class": "GenericError", "desc": "Parameter 'driver' is missing"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + *** done +diff --git a/tests/qemu-iotests/108.out b/tests/qemu-iotests/108.out +index b5401d7..b9c876b 100644 +--- a/tests/qemu-iotests/108.out ++++ b/tests/qemu-iotests/108.out +@@ -173,8 +173,8 @@ OK: Reftable is where we expect it + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "create"}} + {"return": {}} + { "execute": "quit" } +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + wrote 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109 +index e207a55..0fb580f 100755 +--- a/tests/qemu-iotests/109 ++++ b/tests/qemu-iotests/109 +@@ -57,13 +57,13 @@ run_qemu() + _launch_qemu -drive file="${source_img}",format=raw,cache=${CACHEMODE},aio=${AIOMODE},id=src + _send_qemu_cmd $QEMU_HANDLE "{ 'execute': 'qmp_capabilities' }" "return" + +- _send_qemu_cmd $QEMU_HANDLE \ ++ capture_events="$qmp_event" _send_qemu_cmd $QEMU_HANDLE \ + "{'execute':'drive-mirror', 'arguments':{ + 'device': 'src', 'target': '$raw_img', $qmp_format + 'mode': 'existing', 'sync': 'full'}}" \ + "return" + +- _send_qemu_cmd $QEMU_HANDLE '' "$qmp_event" ++ capture_events="$qmp_event JOB_STATUS_CHANGE" _wait_event $QEMU_HANDLE "$qmp_event" + if test "$qmp_event" = BLOCK_JOB_ERROR; then + _send_qemu_cmd $QEMU_HANDLE '' '"status": "null"' + fi +diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out +index 965c9a6..3ae8552 100644 +--- a/tests/qemu-iotests/109.out ++++ b/tests/qemu-iotests/109.out +@@ -7,7 +7,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -23,8 +23,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"execute":"query-block-jobs"} + {"return": []} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + { 'execute': 'qmp_capabilities' } +@@ -35,12 +35,10 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -50,6 +48,7 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + + === Writing a qcow2 header into raw === +@@ -59,7 +58,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -75,8 +74,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"execute":"query-block-jobs"} + {"return": []} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + { 'execute': 'qmp_capabilities' } +@@ -87,12 +86,10 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 197120, "offset": 197120, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -102,6 +99,7 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + + === Writing a qed header into raw === +@@ -111,7 +109,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -127,8 +125,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"execute":"query-block-jobs"} + {"return": []} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + { 'execute': 'qmp_capabilities' } +@@ -139,12 +137,10 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -154,6 +150,7 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + + === Writing a vdi header into raw === +@@ -163,7 +160,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -179,8 +176,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"execute":"query-block-jobs"} + {"return": []} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + { 'execute': 'qmp_capabilities' } +@@ -191,12 +188,10 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -206,6 +201,7 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + + === Writing a vmdk header into raw === +@@ -215,7 +211,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -231,8 +227,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"execute":"query-block-jobs"} + {"return": []} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + { 'execute': 'qmp_capabilities' } +@@ -243,12 +239,10 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 65536, "offset": 65536, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -258,6 +252,7 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + + === Writing a vpc header into raw === +@@ -267,7 +262,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -283,8 +278,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"execute":"query-block-jobs"} + {"return": []} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + { 'execute': 'qmp_capabilities' } +@@ -295,12 +290,10 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -310,6 +303,7 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + + === Copying sample image empty.bochs into raw === +@@ -318,7 +312,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -334,8 +328,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"execute":"query-block-jobs"} + {"return": []} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + { 'execute': 'qmp_capabilities' } +@@ -346,12 +340,10 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -361,6 +353,7 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + + === Copying sample image iotest-dirtylog-10G-4M.vhdx into raw === +@@ -369,7 +362,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -385,8 +378,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"execute":"query-block-jobs"} + {"return": []} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + { 'execute': 'qmp_capabilities' } +@@ -397,12 +390,10 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 31457280, "offset": 31457280, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -412,6 +403,7 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + + === Copying sample image parallels-v1 into raw === +@@ -420,7 +412,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -436,8 +428,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"execute":"query-block-jobs"} + {"return": []} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + { 'execute': 'qmp_capabilities' } +@@ -448,12 +440,10 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -463,6 +453,7 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + + === Copying sample image simple-pattern.cloop into raw === +@@ -471,7 +462,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -487,8 +478,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"execute":"query-block-jobs"} + {"return": []} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + { 'execute': 'qmp_capabilities' } +@@ -499,12 +490,10 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2048, "offset": 2048, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -514,6 +503,7 @@ read 512/512 bytes at offset 0 + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + + === Write legitimate MBR into raw === +@@ -522,7 +512,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE + { 'execute': 'qmp_capabilities' } + {"return": {}} + {'execute':'drive-mirror', 'arguments':{ +- 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', ++ 'device': 'src', 'target': 'TEST_DIR/t.IMGFMT', + 'mode': 'existing', 'sync': 'full'}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. + Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +@@ -530,12 +520,10 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -545,6 +533,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + { 'execute': 'qmp_capabilities' } + {"return": {}} +@@ -554,12 +543,10 @@ Images are identical. + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} + {"execute":"query-block-jobs"} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror", "actively-synced": false}]} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} +@@ -569,5 +556,6 @@ Images are identical. + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} ++{"return": {}} + Images are identical. + *** done +diff --git a/tests/qemu-iotests/117.out b/tests/qemu-iotests/117.out +index 735ffd2..1cea9e0 100644 +--- a/tests/qemu-iotests/117.out ++++ b/tests/qemu-iotests/117.out +@@ -18,8 +18,8 @@ wrote 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": ""} + { 'execute': 'quit' } +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + No errors were found on the image. + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +diff --git a/tests/qemu-iotests/120.out b/tests/qemu-iotests/120.out +index 0744c1f..35d84a5 100644 +--- a/tests/qemu-iotests/120.out ++++ b/tests/qemu-iotests/120.out +@@ -5,8 +5,8 @@ QMP_VERSION + wrote 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": ""} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + read 65536/65536 bytes at offset 0 +diff --git a/tests/qemu-iotests/127.out b/tests/qemu-iotests/127.out +index 1685c48..dd8c4a8 100644 +--- a/tests/qemu-iotests/127.out ++++ b/tests/qemu-iotests/127.out +@@ -28,6 +28,6 @@ wrote 42/42 bytes at offset 0 + { 'execute': 'quit' } + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "mirror"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + *** done +diff --git a/tests/qemu-iotests/140.out b/tests/qemu-iotests/140.out +index 312f76d..3286644 100644 +--- a/tests/qemu-iotests/140.out ++++ b/tests/qemu-iotests/140.out +@@ -19,6 +19,6 @@ read 65536/65536 bytes at offset 0 + qemu-io: can't open device nbd+unix:///drv?socket=SOCK_DIR/nbd: Requested export not available + server reported: export 'drv' not present + { 'execute': 'quit' } +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + *** done +diff --git a/tests/qemu-iotests/143.out b/tests/qemu-iotests/143.out +index 9ec5888..d6afa32 100644 +--- a/tests/qemu-iotests/143.out ++++ b/tests/qemu-iotests/143.out +@@ -10,6 +10,6 @@ server reported: export 'no_such_export' not present + qemu-io: can't open device nbd+unix:///aa--aa1?socket=SOCK_DIR/nbd: Requested export not available + server reported: export 'aa--aa...' not present + { 'execute': 'quit' } +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + *** done +diff --git a/tests/qemu-iotests/156.out b/tests/qemu-iotests/156.out +index 4a22f0c..07e5e83 100644 +--- a/tests/qemu-iotests/156.out ++++ b/tests/qemu-iotests/156.out +@@ -72,8 +72,8 @@ read 65536/65536 bytes at offset 196608 + {"return": ""} + + { 'execute': 'quit' } +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +diff --git a/tests/qemu-iotests/176.out b/tests/qemu-iotests/176.out +index 9d09b60..45e9153 100644 +--- a/tests/qemu-iotests/176.out ++++ b/tests/qemu-iotests/176.out +@@ -169,8 +169,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + wrote 196608/196608 bytes at offset 2147287040 + 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + wrote 131072/131072 bytes at offset 2147352576 +@@ -206,8 +206,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {"sha256": HASH}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + === Test pass bitmap.1 === + +@@ -218,8 +218,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + wrote 196608/196608 bytes at offset 2147287040 + 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + wrote 131072/131072 bytes at offset 2147352576 +@@ -256,8 +256,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {"sha256": HASH}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + === Test pass bitmap.2 === + +@@ -268,8 +268,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + wrote 196608/196608 bytes at offset 2147287040 + 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + wrote 131072/131072 bytes at offset 2147352576 +@@ -306,8 +306,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {"sha256": HASH}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + === Test pass bitmap.3 === + +@@ -318,8 +318,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + wrote 196608/196608 bytes at offset 2147287040 + 192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + wrote 131072/131072 bytes at offset 2147352576 +@@ -353,6 +353,6 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {"sha256": HASH}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + *** done +diff --git a/tests/qemu-iotests/182.out b/tests/qemu-iotests/182.out +index 57f7265..83fc1a4 100644 +--- a/tests/qemu-iotests/182.out ++++ b/tests/qemu-iotests/182.out +@@ -53,6 +53,6 @@ Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 cluster_size=65536 extended_l2= + {'execute': 'qmp_capabilities'} + {"return": {}} + {'execute': 'quit'} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + *** done +diff --git a/tests/qemu-iotests/183.out b/tests/qemu-iotests/183.out +index fd9c2e5..51aa41c 100644 +--- a/tests/qemu-iotests/183.out ++++ b/tests/qemu-iotests/183.out +@@ -53,11 +53,11 @@ wrote 65536/65536 bytes at offset 1048576 + === Shut down and check image === + + {"execute":"quit"} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"return": {}} + {"execute":"quit"} +-{"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + No errors were found on the image. + No errors were found on the image. + wrote 65536/65536 bytes at offset 1048576 +diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out +index 77e5489..e8f631f 100644 +--- a/tests/qemu-iotests/184.out ++++ b/tests/qemu-iotests/184.out +@@ -90,10 +90,6 @@ Testing: + ] + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -104,6 +100,10 @@ Testing: + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + + == property changes in ThrottleGroup == +@@ -170,10 +170,6 @@ Testing: + } + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -184,6 +180,10 @@ Testing: + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + + == object creation/set errors == +@@ -212,10 +212,6 @@ Testing: + } + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -226,6 +222,10 @@ Testing: + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + + == don't specify group == +@@ -248,10 +248,6 @@ Testing: + } + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -262,6 +258,10 @@ Testing: + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + + *** done +diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185 +index 2ae0a85..17489fb 100755 +--- a/tests/qemu-iotests/185 ++++ b/tests/qemu-iotests/185 +@@ -344,14 +344,14 @@ wait_for_job_and_quit() { + + sleep 1 + ++ # List of expected events ++ capture_events='BLOCK_JOB_CANCELLED JOB_STATUS_CHANGE SHUTDOWN' ++ + _send_qemu_cmd $h \ + '{"execute": "quit"}' \ + 'return' + +- # List of expected events +- capture_events='BLOCK_JOB_CANCELLED JOB_STATUS_CHANGE SHUTDOWN' + _wait_event $h 'SHUTDOWN' +- QEMU_EVENTS= # Ignore all JOB_STATUS_CHANGE events that came before SHUTDOWN + _wait_event $h 'JOB_STATUS_CHANGE' # standby + _wait_event $h 'JOB_STATUS_CHANGE' # ready + _wait_event $h 'JOB_STATUS_CHANGE' # standby +diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out +index 7292c26..6af0953 100644 +--- a/tests/qemu-iotests/185.out ++++ b/tests/qemu-iotests/185.out +@@ -40,9 +40,16 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off comp + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} + {"return": {}} + { 'execute': 'quit' } +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "disk"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "commit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "disk"}} ++{"return": {}} + + === Start active commit job and exit qemu === + +@@ -56,9 +63,16 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off comp + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} + {"return": {}} + { 'execute': 'quit' } +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "disk"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "commit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "disk"}} ++{"return": {}} + + === Start mirror job and exit qemu === + +@@ -75,9 +89,16 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} + {"return": {}} + { 'execute': 'quit' } +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "disk"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "disk"}} ++{"return": {}} + + === Start backup job and exit qemu === + +@@ -97,9 +118,16 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} + {"return": {}} + { 'execute': 'quit' } +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "disk"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 65536, "speed": 65536, "type": "backup"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "disk"}} ++{"return": {}} + + === Start streaming job and exit qemu === + +@@ -112,9 +140,16 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} + {"return": {}} + { 'execute': 'quit' } +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "disk"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "stream"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "disk"}} ++{"return": {}} + No errors were found on the image. + + === Start mirror to throttled QSD and exit qemu === +diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out +index ea88777..c3309e4 100644 +--- a/tests/qemu-iotests/191.out ++++ b/tests/qemu-iotests/191.out +@@ -379,10 +379,6 @@ wrote 65536/65536 bytes at offset 1048576 + } + { 'execute': 'quit' } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -393,6 +389,10 @@ wrote 65536/65536 bytes at offset 1048576 + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + image: TEST_DIR/t.IMGFMT + file format: IMGFMT + virtual size: 64 MiB (67108864 bytes) +@@ -797,10 +797,6 @@ wrote 65536/65536 bytes at offset 1048576 + } + { 'execute': 'quit' } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -811,6 +807,10 @@ wrote 65536/65536 bytes at offset 1048576 + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + image: TEST_DIR/t.IMGFMT + file format: IMGFMT + virtual size: 64 MiB (67108864 bytes) +diff --git a/tests/qemu-iotests/195.out b/tests/qemu-iotests/195.out +index ec84df5..91717d3 100644 +--- a/tests/qemu-iotests/195.out ++++ b/tests/qemu-iotests/195.out +@@ -18,10 +18,6 @@ Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,backing.node-name=mid + } + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -32,6 +28,10 @@ Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,backing.node-name=mid + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + image: TEST_DIR/t.IMGFMT.mid + file format: IMGFMT +@@ -56,10 +56,6 @@ Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,node-name=top + } + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -70,6 +66,10 @@ Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,node-name=top + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + image: TEST_DIR/t.IMGFMT + file format: IMGFMT +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +index e5e7f42..5f5b42e 100644 +--- a/tests/qemu-iotests/223.out ++++ b/tests/qemu-iotests/223.out +@@ -11,8 +11,8 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + + === Write part of the file under active bitmap === +@@ -145,14 +145,14 @@ read 2097152/2097152 bytes at offset 2097152 + + {"execute":"nbd-server-remove", + "arguments":{"name":"n"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n"}} + {"return": {}} + {"execute":"nbd-server-remove", + "arguments":{"name":"n2"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n2"}} + {"return": {}} + {"execute":"nbd-server-remove", + "arguments":{"name":"n2"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n2"}} + {"error": {"class": "GenericError", "desc": "Export 'n2' is not found"}} + {"execute":"nbd-server-stop"} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n3"}} +@@ -267,14 +267,14 @@ read 2097152/2097152 bytes at offset 2097152 + + {"execute":"nbd-server-remove", + "arguments":{"name":"n"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n"}} + {"return": {}} + {"execute":"nbd-server-remove", + "arguments":{"name":"n2"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n2"}} + {"return": {}} + {"execute":"nbd-server-remove", + "arguments":{"name":"n2"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n2"}} + {"error": {"class": "GenericError", "desc": "Export 'n2' is not found"}} + {"execute":"nbd-server-stop"} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n3"}} +@@ -282,8 +282,8 @@ read 2097152/2097152 bytes at offset 2097152 + {"execute":"nbd-server-stop"} + {"error": {"class": "GenericError", "desc": "NBD server not running"}} + {"execute":"quit"} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + + === Use qemu-nbd as server === + +diff --git a/tests/qemu-iotests/227.out b/tests/qemu-iotests/227.out +index a947b1a..d6a1d4e 100644 +--- a/tests/qemu-iotests/227.out ++++ b/tests/qemu-iotests/227.out +@@ -55,10 +55,6 @@ Testing: -drive driver=null-co,read-zeroes=on,if=virtio + ] + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -69,6 +65,10 @@ Testing: -drive driver=null-co,read-zeroes=on,if=virtio + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + + === blockstats with -drive if=none === +@@ -125,10 +125,6 @@ Testing: -drive driver=null-co,if=none + ] + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -139,6 +135,10 @@ Testing: -drive driver=null-co,if=none + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + + === blockstats with -blockdev === +@@ -156,10 +156,6 @@ Testing: -blockdev driver=null-co,node-name=null + ] + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -170,6 +166,10 @@ Testing: -blockdev driver=null-co,node-name=null + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + + === blockstats with -blockdev and -device === +@@ -227,10 +227,6 @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-b + ] + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -241,5 +237,9 @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-b + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + *** done +diff --git a/tests/qemu-iotests/247.out b/tests/qemu-iotests/247.out +index e909e83..7d252e7 100644 +--- a/tests/qemu-iotests/247.out ++++ b/tests/qemu-iotests/247.out +@@ -17,6 +17,6 @@ QMP_VERSION + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + *** done +diff --git a/tests/qemu-iotests/273.out b/tests/qemu-iotests/273.out +index 6a74a81..71843f0 100644 +--- a/tests/qemu-iotests/273.out ++++ b/tests/qemu-iotests/273.out +@@ -283,10 +283,6 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev + } + } + { +- "return": { +- } +-} +-{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP +@@ -297,5 +293,9 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev + "reason": "host-qmp-quit" + } + } ++{ ++ "return": { ++ } ++} + + *** done +diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308 +index de12b2b..ea81dc4 100755 +--- a/tests/qemu-iotests/308 ++++ b/tests/qemu-iotests/308 +@@ -77,6 +77,7 @@ fuse_export_add() + # $1: Export ID + fuse_export_del() + { ++ capture_events="BLOCK_EXPORT_DELETED" \ + _send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'block-export-del', + 'arguments': { +@@ -84,8 +85,7 @@ fuse_export_del() + } }" \ + 'return' + +- _send_qemu_cmd $QEMU_HANDLE \ +- '' \ ++ _wait_event $QEMU_HANDLE \ + 'BLOCK_EXPORT_DELETED' + } + +diff --git a/tests/qemu-iotests/308.out b/tests/qemu-iotests/308.out +index d576713..e5e2336 100644 +--- a/tests/qemu-iotests/308.out ++++ b/tests/qemu-iotests/308.out +@@ -165,9 +165,9 @@ OK: Post-truncate image size is as expected + + === Tear down === + {'execute': 'quit'} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export-mp"}} ++{"return": {}} + + === Compare copy with original === + Images are identical. +@@ -201,9 +201,9 @@ wrote 67108864/67108864 bytes at offset 0 + read 67108864/67108864 bytes at offset 0 + 64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {'execute': 'quit'} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}} ++{"return": {}} + read 67108864/67108864 bytes at offset 0 + 64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + *** done +diff --git a/tests/qemu-iotests/tests/file-io-error b/tests/qemu-iotests/tests/file-io-error +index 88ee5f6..fb8db73 100755 +--- a/tests/qemu-iotests/tests/file-io-error ++++ b/tests/qemu-iotests/tests/file-io-error +@@ -99,13 +99,12 @@ echo + $QEMU_IO -f file -c 'write 0 64M' "$TEST_DIR/fuse-export" | _filter_qemu_io + echo + +-_send_qemu_cmd $QEMU_HANDLE \ ++capture_events=BLOCK_EXPORT_DELETED _send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'block-export-del', + 'arguments': {'id': 'exp0'}}" \ + 'return' + +-_send_qemu_cmd $QEMU_HANDLE \ +- '' \ ++_wait_event $QEMU_HANDLE \ + 'BLOCK_EXPORT_DELETED' + + _send_qemu_cmd $QEMU_HANDLE \ +diff --git a/tests/qemu-iotests/tests/iothreads-resize.out b/tests/qemu-iotests/tests/iothreads-resize.out +index 2ca5a9d..2967ac8 100644 +--- a/tests/qemu-iotests/tests/iothreads-resize.out ++++ b/tests/qemu-iotests/tests/iothreads-resize.out +@@ -3,8 +3,8 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + QMP_VERSION + {"return": {}} + {"return": {}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++{"return": {}} + image: TEST_DIR/t.IMGFMT + file format: IMGFMT + virtual size: 128 MiB (134217728 bytes) +diff --git a/tests/qemu-iotests/tests/qsd-jobs.out b/tests/qemu-iotests/tests/qsd-jobs.out +index c1bc9b8..aa6b6d1 100644 +--- a/tests/qemu-iotests/tests/qsd-jobs.out ++++ b/tests/qemu-iotests/tests/qsd-jobs.out +@@ -7,8 +7,8 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/ + QMP_VERSION + {"return": {}} + {"return": {}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} ++{"return": {}} + + === Streaming can't get permission on base node === + +@@ -17,6 +17,6 @@ QMP_VERSION + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} + {"error": {"class": "GenericError", "desc": "Permission conflict on node 'fmt_base': permissions 'write' are both required by an unnamed block device (uses node 'fmt_base' as 'root' child) and unshared by stream job 'job0' (uses node 'fmt_base' as 'intermediate node' child)."}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export1"}} ++{"return": {}} + *** done +-- +1.8.3.1 + diff --git a/0062-qtest-bump-aspeed_smc-test-timeout-to-6-minutes.patch b/0062-qtest-bump-aspeed_smc-test-timeout-to-6-minutes.patch new file mode 100644 index 0000000000000000000000000000000000000000..edb5db45cb45dc177219625ebaf8789f1a0944dc --- /dev/null +++ b/0062-qtest-bump-aspeed_smc-test-timeout-to-6-minutes.patch @@ -0,0 +1,38 @@ +From ce34d02f91a10b43940e8ed186c9c334cb571a15 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Fri, 15 Dec 2023 08:03:51 +0100 +Subject: [PATCH 068/293] qtest: bump aspeed_smc-test timeout to 6 minutes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On a loaded system with --enable-debug, this test can take longer than +5 minutes. Raising the timeout to 6 minutes gives greater headroom for +such situations. + +Signed-off-by: Daniel P. Berrangé +[thuth: Increase the timeout to 6 minutes for very loaded systems] +Signed-off-by: Thomas Huth +Message-Id: <20231215070357.10888-11-thuth@redhat.com> +Signed-off-by: Alex Bennée +(cherry picked from commit e8a12fe31f776c60fec993513cd1b1e66c2b8e29) +Signed-off-by: Michael Tokarev +(Mjt: context fixup in tests/qtest/meson.build) +--- + tests/qtest/meson.build | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build +index 47dabf9..fc14ae9 100644 +--- a/tests/qtest/meson.build ++++ b/tests/qtest/meson.build +@@ -1,5 +1,6 @@ + slow_qtests = { + 'ahci-test' : 60, ++ 'aspeed_smc-test': 360, + 'bios-tables-test' : 120, + 'boot-serial-test' : 60, + 'migration-test' : 150, +-- +1.8.3.1 + diff --git a/0063-target-xtensa-fix-OOB-TLB-entry-access.patch b/0063-target-xtensa-fix-OOB-TLB-entry-access.patch new file mode 100644 index 0000000000000000000000000000000000000000..20333fed6896c3dccf2aeb994573ab09b38f38e9 --- /dev/null +++ b/0063-target-xtensa-fix-OOB-TLB-entry-access.patch @@ -0,0 +1,140 @@ +From 553e53b4421ed5b671dc79ab32e82cf7ba9ad229 Mon Sep 17 00:00:00 2001 +From: Max Filippov +Date: Fri, 15 Dec 2023 04:03:07 -0800 +Subject: [PATCH 069/293] target/xtensa: fix OOB TLB entry access + +r[id]tlb[01], [iw][id]tlb opcodes use TLB way index passed in a register +by the guest. The host uses 3 bits of the index for ITLB indexing and 4 +bits for DTLB, but there's only 7 entries in the ITLB array and 10 in +the DTLB array, so a malicious guest may trigger out-of-bound access to +these arrays. + +Change split_tlb_entry_spec return type to bool to indicate whether TLB +way passed to it is valid. Change get_tlb_entry to return NULL in case +invalid TLB way is requested. Add assertion to xtensa_tlb_get_entry that +requested TLB way and entry indices are valid. Add checks to the +[rwi]tlb helpers that requested TLB way is valid and return 0 or do +nothing when it's not. + +Cc: qemu-stable@nongnu.org +Fixes: b67ea0cd7441 ("target-xtensa: implement memory protection options") +Signed-off-by: Max Filippov +Reviewed-by: Peter Maydell +Message-id: 20231215120307.545381-1-jcmvbkbc@gmail.com +Signed-off-by: Peter Maydell +(cherry picked from commit 604927e357c2b292c70826e4ce42574ad126ef32) +Signed-off-by: Michael Tokarev +--- + target/xtensa/mmu_helper.c | 47 ++++++++++++++++++++++++++++++++++------------ + 1 file changed, 35 insertions(+), 12 deletions(-) + +diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c +index 12552a3..2fda4e8 100644 +--- a/target/xtensa/mmu_helper.c ++++ b/target/xtensa/mmu_helper.c +@@ -224,22 +224,31 @@ static void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, + * Split TLB address into TLB way, entry index and VPN (with index). + * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format + */ +-static void split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb, +- uint32_t *vpn, uint32_t *wi, uint32_t *ei) ++static bool split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb, ++ uint32_t *vpn, uint32_t *wi, uint32_t *ei) + { + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + *wi = v & (dtlb ? 0xf : 0x7); +- split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei); ++ if (*wi < (dtlb ? env->config->dtlb.nways : env->config->itlb.nways)) { ++ split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei); ++ return true; ++ } else { ++ return false; ++ } + } else { + *vpn = v & REGION_PAGE_MASK; + *wi = 0; + *ei = (v >> 29) & 0x7; ++ return true; + } + } + + static xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env, bool dtlb, + unsigned wi, unsigned ei) + { ++ const xtensa_tlb *tlb = dtlb ? &env->config->dtlb : &env->config->itlb; ++ ++ assert(wi < tlb->nways && ei < tlb->way_size[wi]); + return dtlb ? + env->dtlb[wi] + ei : + env->itlb[wi] + ei; +@@ -252,11 +261,14 @@ static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env, + uint32_t wi; + uint32_t ei; + +- split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei); +- if (pwi) { +- *pwi = wi; ++ if (split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei)) { ++ if (pwi) { ++ *pwi = wi; ++ } ++ return xtensa_tlb_get_entry(env, dtlb, wi, ei); ++ } else { ++ return NULL; + } +- return xtensa_tlb_get_entry(env, dtlb, wi, ei); + } + + static void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env, +@@ -482,7 +494,12 @@ uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + uint32_t wi; + const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi); +- return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid; ++ ++ if (entry) { ++ return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid; ++ } else { ++ return 0; ++ } + } else { + return v & REGION_PAGE_MASK; + } +@@ -491,7 +508,12 @@ uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) + uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) + { + const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, NULL); +- return entry->paddr | entry->attr; ++ ++ if (entry) { ++ return entry->paddr | entry->attr; ++ } else { ++ return 0; ++ } + } + + void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) +@@ -499,7 +521,7 @@ void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) + if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + uint32_t wi; + xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi); +- if (entry->variable && entry->asid) { ++ if (entry && entry->variable && entry->asid) { + tlb_flush_page(env_cpu(env), entry->vaddr); + entry->asid = 0; + } +@@ -537,8 +559,9 @@ void HELPER(wtlb)(CPUXtensaState *env, uint32_t p, uint32_t v, uint32_t dtlb) + uint32_t vpn; + uint32_t wi; + uint32_t ei; +- split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei); +- xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p); ++ if (split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei)) { ++ xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p); ++ } + } + + /*! +-- +1.8.3.1 + diff --git a/0064-target-arm-Fix-A64-scalar-SQSHRN-and-SQRSHRN.patch b/0064-target-arm-Fix-A64-scalar-SQSHRN-and-SQRSHRN.patch new file mode 100644 index 0000000000000000000000000000000000000000..eb187a6b427d17cf8d46ca5012777c58e577e13b --- /dev/null +++ b/0064-target-arm-Fix-A64-scalar-SQSHRN-and-SQRSHRN.patch @@ -0,0 +1,52 @@ +From 570e624426421a37fa97b04b1de2d096281530bb Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Tue, 23 Jan 2024 15:34:16 +0000 +Subject: [PATCH 070/293] target/arm: Fix A64 scalar SQSHRN and SQRSHRN + +In commit 1b7bc9b5c8bf374dd we changed handle_vec_simd_sqshrn() so +that instead of starting with a 0 value and depositing in each new +element from the narrowing operation, it instead started with the raw +result of the narrowing operation of the first element. + +This is fine in the vector case, because the deposit operations for +the second and subsequent elements will always overwrite any higher +bits that might have been in the first element's result value in +tcg_rd. However in the scalar case we only go through this loop +once. The effect is that for a signed narrowing operation, if the +result is negative then we will now return a value where the bits +above the first element are incorrectly 1 (because the narrowfn +returns a sign-extended result, not one that is truncated to the +element size). + +Fix this by using an extract operation to get exactly the correct +bits of the output of the narrowfn for element 1, instead of a +plain move. + +Cc: qemu-stable@nongnu.org +Fixes: 1b7bc9b5c8bf374dd3 ("target/arm: Avoid tcg_const_ptr in handle_vec_simd_sqshrn") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2089 +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Message-id: 20240123153416.877308-1-peter.maydell@linaro.org +(cherry picked from commit 6fffc8378562c7fea6290c430b4f653f830a4c1a) +Signed-off-by: Michael Tokarev +--- + target/arm/tcg/translate-a64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c +index a2e49c3..f2d05c5 100644 +--- a/target/arm/tcg/translate-a64.c ++++ b/target/arm/tcg/translate-a64.c +@@ -8221,7 +8221,7 @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, + narrowfn(tcg_rd_narrowed, tcg_env, tcg_rd); + tcg_gen_extu_i32_i64(tcg_rd, tcg_rd_narrowed); + if (i == 0) { +- tcg_gen_mov_i64(tcg_final, tcg_rd); ++ tcg_gen_extract_i64(tcg_final, tcg_rd, 0, esize); + } else { + tcg_gen_deposit_i64(tcg_final, tcg_final, tcg_rd, esize * i, esize); + } +-- +1.8.3.1 + diff --git a/0065-target-arm-Fix-incorrect-aa64_tidcp1-feature-check.patch b/0065-target-arm-Fix-incorrect-aa64_tidcp1-feature-check.patch new file mode 100644 index 0000000000000000000000000000000000000000..c0b1bbf4748afeb139973f26e562c7b36580c679 --- /dev/null +++ b/0065-target-arm-Fix-incorrect-aa64_tidcp1-feature-check.patch @@ -0,0 +1,38 @@ +From 45b3ce5e83a6e6677ed9197ed203d6076d25848e Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Tue, 23 Jan 2024 16:03:33 +0000 +Subject: [PATCH 071/293] target/arm: Fix incorrect aa64_tidcp1 feature check + +A typo in the implementation of isar_feature_aa64_tidcp1() means we +were checking the field in the wrong ID register, so we might have +provided the feature on CPUs that don't have it and not provided +it on CPUs that should have it. Correct this bug. + +Cc: qemu-stable@nongnu.org +Fixes: 9cd0c0dec97be9 "target/arm: Implement FEAT_TIDCP1" +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2120 +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Message-id: 20240123160333.958841-1-peter.maydell@linaro.org +(cherry picked from commit ee0a2e3c9d2991a11c13ffadb15e4d0add43c257) +Signed-off-by: Michael Tokarev +--- + target/arm/cpu-features.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index 954d358..165a497 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -771,7 +771,7 @@ static inline bool isar_feature_aa64_hcx(const ARMISARegisters *id) + + static inline bool isar_feature_aa64_tidcp1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR1, TIDCP1) != 0; ++ return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, TIDCP1) != 0; + } + + static inline bool isar_feature_aa64_hafs(const ARMISARegisters *id) +-- +1.8.3.1 + diff --git a/0066-Update-version-for-8.2.1-release.patch b/0066-Update-version-for-8.2.1-release.patch new file mode 100644 index 0000000000000000000000000000000000000000..43be6ec5e6e0121d5d09b384b5b8f91c11178ed8 --- /dev/null +++ b/0066-Update-version-for-8.2.1-release.patch @@ -0,0 +1,20 @@ +From f48c205fb42be48e2e47b7e1cd9a2802e5ca17b0 Mon Sep 17 00:00:00 2001 +From: Michael Tokarev +Date: Mon, 29 Jan 2024 14:20:06 +0300 +Subject: [PATCH 072/293] Update version for 8.2.1 release + +Signed-off-by: Michael Tokarev +--- + VERSION | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/VERSION b/VERSION +index fbb9ea1..2b0aa21 100644 +--- a/VERSION ++++ b/VERSION +@@ -1 +1 @@ +-8.2.0 ++8.2.1 +-- +1.8.3.1 + diff --git a/0067-migration-Plug-memory-leak-on-HMP-migrate-error-path.patch b/0067-migration-Plug-memory-leak-on-HMP-migrate-error-path.patch new file mode 100644 index 0000000000000000000000000000000000000000..d34709ca65c6287c25b1c994ef4fa882d9c1e447 --- /dev/null +++ b/0067-migration-Plug-memory-leak-on-HMP-migrate-error-path.patch @@ -0,0 +1,45 @@ +From e589e5ade7e7dc1f14eacc1670646439e4c07284 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 17 Jan 2024 15:07:22 +0100 +Subject: [PATCH 073/293] migration: Plug memory leak on HMP migrate error path + +hmp_migrate() leaks @caps when qmp_migrate() fails. Plug the leak +with g_autoptr(). + +Fixes: 967f2de5c9ec (migration: Implement MigrateChannelList to hmp migration flow.) v8.2.0-rc0 +Fixes: CID 1533125 +Signed-off-by: Markus Armbruster +Link: https://lore.kernel.org/r/20240117140722.3979657-1-armbru@redhat.com +[peterx: fix CID number as reported by Peter Maydell] +Signed-off-by: Peter Xu +(cherry picked from commit 918f620d30a9b0095b7824b8d77a2d6059a439d9) +Signed-off-by: Michael Tokarev +--- + migration/migration-hmp-cmds.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c +index 86ae832..2faa5ca 100644 +--- a/migration/migration-hmp-cmds.c ++++ b/migration/migration-hmp-cmds.c +@@ -762,7 +762,7 @@ void hmp_migrate(Monitor *mon, const QDict *qdict) + bool resume = qdict_get_try_bool(qdict, "resume", false); + const char *uri = qdict_get_str(qdict, "uri"); + Error *err = NULL; +- MigrationChannelList *caps = NULL; ++ g_autoptr(MigrationChannelList) caps = NULL; + g_autoptr(MigrationChannel) channel = NULL; + + if (inc) { +@@ -787,8 +787,6 @@ void hmp_migrate(Monitor *mon, const QDict *qdict) + return; + } + +- qapi_free_MigrationChannelList(caps); +- + if (!detach) { + HMPMigrationStatus *status; + +-- +1.8.3.1 + diff --git a/0068-migration-Fix-use-after-free-of-migration-state-obje.patch b/0068-migration-Fix-use-after-free-of-migration-state-obje.patch new file mode 100644 index 0000000000000000000000000000000000000000..0ff41b2ab735d1138af7492e9a1f425d8d8cd5f8 --- /dev/null +++ b/0068-migration-Fix-use-after-free-of-migration-state-obje.patch @@ -0,0 +1,54 @@ +From 106aa13c5bbb10d1742d9f2be1ac73a4918f6a27 Mon Sep 17 00:00:00 2001 +From: Fabiano Rosas +Date: Fri, 19 Jan 2024 20:39:18 -0300 +Subject: [PATCH 074/293] migration: Fix use-after-free of migration state + object + +We're currently allowing the process_incoming_migration_bh bottom-half +to run without holding a reference to the 'current_migration' object, +which leads to a segmentation fault if the BH is still live after +migration_shutdown() has dropped the last reference to +current_migration. + +In my system the bug manifests as migrate_multifd() returning true +when it shouldn't and multifd_load_shutdown() calling +multifd_recv_terminate_threads() which crashes due to an uninitialized +multifd_recv_state. + +Fix the issue by holding a reference to the object when scheduling the +BH and dropping it before returning from the BH. The same is already +done for the cleanup_bh at migrate_fd_cleanup_schedule(). + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1969 +Signed-off-by: Fabiano Rosas +Link: https://lore.kernel.org/r/20240119233922.32588-2-farosas@suse.de +Signed-off-by: Peter Xu +(cherry picked from commit 27eb8499edb2bc952c29ddae0bdac9fc959bf7b1) +Signed-off-by: Michael Tokarev +--- + migration/migration.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/migration/migration.c b/migration/migration.c +index 3ce04b2..ee5e0ba 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -650,6 +650,7 @@ static void process_incoming_migration_bh(void *opaque) + MIGRATION_STATUS_COMPLETED); + qemu_bh_delete(mis->bh); + migration_incoming_state_destroy(); ++ object_unref(OBJECT(migrate_get_current())); + } + + static void coroutine_fn +@@ -708,6 +709,7 @@ process_incoming_migration_co(void *opaque) + } + + mis->bh = qemu_bh_new(process_incoming_migration_bh, mis); ++ object_ref(OBJECT(migrate_get_current())); + qemu_bh_schedule(mis->bh); + return; + fail: +-- +1.8.3.1 + diff --git a/0069-vfio-pci-Clear-MSI-X-IRQ-index-always.patch b/0069-vfio-pci-Clear-MSI-X-IRQ-index-always.patch new file mode 100644 index 0000000000000000000000000000000000000000..3c615d36cdcb7d5be2e27f57848d26d988c15c81 --- /dev/null +++ b/0069-vfio-pci-Clear-MSI-X-IRQ-index-always.patch @@ -0,0 +1,54 @@ +From b79a2ef0d4dc6b8a4093334db29f7c221c1ac8bd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= +Date: Thu, 25 Jan 2024 14:27:36 +0100 +Subject: [PATCH 075/293] vfio/pci: Clear MSI-X IRQ index always +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When doing device assignment of a physical device, MSI-X can be +enabled with no vectors enabled and this sets the IRQ index to +VFIO_PCI_MSIX_IRQ_INDEX. However, when MSI-X is disabled, the IRQ +index is left untouched if no vectors are in use. Then, when INTx +is enabled, the IRQ index value is considered incompatible (set to +MSI-X) and VFIO_DEVICE_SET_IRQS fails. QEMU complains with : + +qemu-system-x86_64: vfio 0000:08:00.0: Failed to set up TRIGGER eventfd signaling for interrupt INTX-0: VFIO_DEVICE_SET_IRQS failure: Invalid argument + +To avoid that, unconditionaly clear the IRQ index when MSI-X is +disabled. + +Buglink: https://issues.redhat.com/browse/RHEL-21293 +Fixes: 5ebffa4e87e7 ("vfio/pci: use an invalid fd to enable MSI-X") +Cc: Jing Liu +Cc: Alex Williamson +Reviewed-by: Alex Williamson +Signed-off-by: Cédric Le Goater +(cherry picked from commit d2b668fca5652760b435ce812a743bba03d2f316) +Signed-off-by: Michael Tokarev +--- + hw/vfio/pci.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index c62c02f..e167bef 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -824,9 +824,11 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) + } + } + +- if (vdev->nr_vectors) { +- vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); +- } ++ /* ++ * Always clear MSI-X IRQ index. A PF device could have enabled ++ * MSI-X with no vectors. See vfio_msix_enable(). ++ */ ++ vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); + + vfio_msi_disable_common(vdev); + vfio_intx_enable(vdev, &err); +-- +1.8.3.1 + diff --git a/0070-Make-uri-optional-for-migrate-QAPI.patch b/0070-Make-uri-optional-for-migrate-QAPI.patch new file mode 100644 index 0000000000000000000000000000000000000000..c8db2547321f1bb98481afc6ecea0ed19997018d --- /dev/null +++ b/0070-Make-uri-optional-for-migrate-QAPI.patch @@ -0,0 +1,34 @@ +From 3837e6dd1ef56e63919b961fa6786fd566fe0311 Mon Sep 17 00:00:00 2001 +From: Het Gala +Date: Tue, 23 Jan 2024 06:42:19 +0000 +Subject: [PATCH 076/293] Make 'uri' optional for migrate QAPI + +'uri' argument should be optional, as 'uri' and 'channels' +arguments are mutally exclusive in nature. + +Fixes: 074dbce5fcce (migration: New migrate and migrate-incoming argument 'channels') +Signed-off-by: Het Gala +Link: https://lore.kernel.org/r/20240123064219.40514-1-het.gala@nutanix.com +Signed-off-by: Peter Xu +(cherry picked from commit 57fd4b4e10756448acd6c90ce041ba8dc9313efc) +Signed-off-by: Michael Tokarev +--- + qapi/migration.json | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qapi/migration.json b/qapi/migration.json +index eb2f883..197d3fa 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -1757,7 +1757,7 @@ + # + ## + { 'command': 'migrate', +- 'data': {'uri': 'str', ++ 'data': {'*uri': 'str', + '*channels': [ 'MigrationChannel' ], + '*blk': { 'type': 'bool', 'features': [ 'deprecated' ] }, + '*inc': { 'type': 'bool', 'features': [ 'deprecated' ] }, +-- +1.8.3.1 + diff --git a/0071-qemu-docs-Update-options-for-graphical-frontends.patch b/0071-qemu-docs-Update-options-for-graphical-frontends.patch new file mode 100644 index 0000000000000000000000000000000000000000..cf9277741e3b45d24b09b950024b068c06622ba2 --- /dev/null +++ b/0071-qemu-docs-Update-options-for-graphical-frontends.patch @@ -0,0 +1,39 @@ +From 84c9704b8e4a347ff74f17c018e58e7f90ca63fc Mon Sep 17 00:00:00 2001 +From: Yihuan Pan +Date: Mon, 22 Jan 2024 12:22:06 +0800 +Subject: [PATCH 077/293] qemu-docs: Update options for graphical frontends + +The command line options `-ctrl-grab` and `-alt-grab` have been removed +in QEMU 7.1. Instead, use the `-display sdl,grab-mod=` option +to specify the grab modifiers. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2103 +Signed-off-by: Yihuan Pan +Signed-off-by: Michael Tokarev +(cherry picked from commit db101376af52e81f740a27f5fa38260ad171323c) +--- + docs/system/keys.rst.inc | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/docs/system/keys.rst.inc b/docs/system/keys.rst.inc +index bd9b8e5..2e2c97a 100644 +--- a/docs/system/keys.rst.inc ++++ b/docs/system/keys.rst.inc +@@ -1,8 +1,9 @@ +-During the graphical emulation, you can use special key combinations to +-change modes. The default key mappings are shown below, but if you use +-``-alt-grab`` then the modifier is Ctrl-Alt-Shift (instead of Ctrl-Alt) +-and if you use ``-ctrl-grab`` then the modifier is the right Ctrl key +-(instead of Ctrl-Alt): ++During the graphical emulation, you can use special key combinations from ++the following table to change modes. By default the modifier is Ctrl-Alt ++(used in the table below) which can be changed with ``-display`` suboption ++``mod=`` where appropriate. For example, ``-display sdl, ++grab-mod=lshift-lctrl-lalt`` changes the modifier key to Ctrl-Alt-Shift, ++while ``-display sdl,grab-mod=rctrl`` changes it to the right Ctrl key. + + Ctrl-Alt-f + Toggle full screen +-- +1.8.3.1 + diff --git a/0072-block-blkio-Make-s-mem_region_alignment-be-64-bits.patch b/0072-block-blkio-Make-s-mem_region_alignment-be-64-bits.patch new file mode 100644 index 0000000000000000000000000000000000000000..d0848cbdcbbeccfaeca0ee2c05ba50fbee9434c7 --- /dev/null +++ b/0072-block-blkio-Make-s-mem_region_alignment-be-64-bits.patch @@ -0,0 +1,47 @@ +From b91715588a101024c644a322ad2f43af50a8d2fd Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 30 Jan 2024 12:20:01 +0000 +Subject: [PATCH 078/293] block/blkio: Make s->mem_region_alignment be 64 bits +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With GCC 14 the code failed to compile on i686 (and was wrong for any +version of GCC): + +../block/blkio.c: In function ‘blkio_file_open’: +../block/blkio.c:857:28: error: passing argument 3 of ‘blkio_get_uint64’ from incompatible pointer type [-Wincompatible-pointer-types] + 857 | &s->mem_region_alignment); + | ^~~~~~~~~~~~~~~~~~~~~~~~ + | | + | size_t * {aka unsigned int *} +In file included from ../block/blkio.c:12: +/usr/include/blkio.h:49:67: note: expected ‘uint64_t *’ {aka ‘long long unsigned int *’} but argument is of type ‘size_t *’ {aka ‘unsigned int *’} + 49 | int blkio_get_uint64(struct blkio *b, const char *name, uint64_t *value); + | ~~~~~~~~~~^~~~~ + +Signed-off-by: Richard W.M. Jones +Message-id: 20240130122006.2977938-1-rjones@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 615eaeab3d318ba239d54141a4251746782f65c1) +Signed-off-by: Michael Tokarev +--- + block/blkio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/blkio.c b/block/blkio.c +index 0a0a6c0..bc2f217 100644 +--- a/block/blkio.c ++++ b/block/blkio.c +@@ -68,7 +68,7 @@ typedef struct { + CoQueue bounce_available; + + /* The value of the "mem-region-alignment" property */ +- size_t mem_region_alignment; ++ uint64_t mem_region_alignment; + + /* Can we skip adding/deleting blkio_mem_regions? */ + bool needs_mem_regions; +-- +1.8.3.1 + diff --git a/0073-target-arm-fix-exception-syndrome-for-AArch32-bkpt-i.patch b/0073-target-arm-fix-exception-syndrome-for-AArch32-bkpt-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..3041d4c011cef321521297a88262f2b3c3128f22 --- /dev/null +++ b/0073-target-arm-fix-exception-syndrome-for-AArch32-bkpt-i.patch @@ -0,0 +1,91 @@ +From 35a60a20f0008a39af39bf39e12a1b07889b4e56 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Kl=C3=B6tzke?= +Date: Thu, 1 Feb 2024 10:57:19 +0000 +Subject: [PATCH 079/293] target/arm: fix exception syndrome for AArch32 bkpt + insn +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Debug exceptions that target AArch32 Hyp mode are reported differently +than on AAarch64. Internally, Qemu uses the AArch64 syndromes. Therefore +such exceptions need to be either converted to a prefetch abort +(breakpoints, vector catch) or a data abort (watchpoints). + +Cc: qemu-stable@nongnu.org +Signed-off-by: Jan Klötzke +Reviewed-by: Richard Henderson +Message-id: 20240127202758.3326381-1-jan.kloetzke@kernkonzept.com +Signed-off-by: Peter Maydell +(cherry picked from commit f670be1aad33e801779af580398895b9455747ee) +Signed-off-by: Michael Tokarev +--- + target/arm/helper.c | 18 ++++++++++++++++++ + target/arm/syndrome.h | 8 ++++++++ + 2 files changed, 26 insertions(+) + +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 2746d3f..6515c5e 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -10823,6 +10823,24 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs) + } + + if (env->exception.target_el == 2) { ++ /* Debug exceptions are reported differently on AArch32 */ ++ switch (syn_get_ec(env->exception.syndrome)) { ++ case EC_BREAKPOINT: ++ case EC_BREAKPOINT_SAME_EL: ++ case EC_AA32_BKPT: ++ case EC_VECTORCATCH: ++ env->exception.syndrome = syn_insn_abort(arm_current_el(env) == 2, ++ 0, 0, 0x22); ++ break; ++ case EC_WATCHPOINT: ++ env->exception.syndrome = syn_set_ec(env->exception.syndrome, ++ EC_DATAABORT); ++ break; ++ case EC_WATCHPOINT_SAME_EL: ++ env->exception.syndrome = syn_set_ec(env->exception.syndrome, ++ EC_DATAABORT_SAME_EL); ++ break; ++ } + arm_cpu_do_interrupt_aarch32_hyp(cs); + return; + } +diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h +index 95454b5..eccb759 100644 +--- a/target/arm/syndrome.h ++++ b/target/arm/syndrome.h +@@ -25,6 +25,8 @@ + #ifndef TARGET_ARM_SYNDROME_H + #define TARGET_ARM_SYNDROME_H + ++#include "qemu/bitops.h" ++ + /* Valid Syndrome Register EC field values */ + enum arm_exception_class { + EC_UNCATEGORIZED = 0x00, +@@ -80,6 +82,7 @@ typedef enum { + SME_ET_InactiveZA, + } SMEExceptionType; + ++#define ARM_EL_EC_LENGTH 6 + #define ARM_EL_EC_SHIFT 26 + #define ARM_EL_IL_SHIFT 25 + #define ARM_EL_ISV_SHIFT 24 +@@ -91,6 +94,11 @@ static inline uint32_t syn_get_ec(uint32_t syn) + return syn >> ARM_EL_EC_SHIFT; + } + ++static inline uint32_t syn_set_ec(uint32_t syn, uint32_t ec) ++{ ++ return deposit32(syn, ARM_EL_EC_SHIFT, ARM_EL_EC_LENGTH, ec); ++} ++ + /* + * Utility functions for constructing various kinds of syndrome value. + * Note that in general we follow the AArch64 syndrome values; in a +-- +1.8.3.1 + diff --git a/0074-system-vl.c-Fix-handling-of-serial-none-serial-somet.patch b/0074-system-vl.c-Fix-handling-of-serial-none-serial-somet.patch new file mode 100644 index 0000000000000000000000000000000000000000..7d348630ea8b783dc4145712aa59e48efae08e4b --- /dev/null +++ b/0074-system-vl.c-Fix-handling-of-serial-none-serial-somet.patch @@ -0,0 +1,89 @@ +From e2a12fa4e7da627516b82ace779d7bfa641aa0de Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Mon, 22 Jan 2024 16:36:06 +0000 +Subject: [PATCH 080/293] system/vl.c: Fix handling of '-serial none -serial + something' +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently if the user passes multiple -serial options on the command +line, we mostly treat those as applying to the different serial +devices in order, so that for example + -serial stdio -serial file:filename +will connect the first serial port to stdio and the second to the +named file. + +The exception to this is the '-serial none' serial device type. This +means "don't allocate this serial device", but a bug means that +following -serial options are not correctly handled, so that + -serial none -serial stdio +has the unexpected effect that stdio is connected to the first serial +port, not the second. + +This is a very long-standing bug that dates back at least as far as +commit 998bbd74b9d81 from 2009. + +Make the 'none' serial type move forward in the indexing of serial +devices like all the other serial types, so that any subsequent +-serial options are correctly handled. + +Note that if your commandline mistakenly had a '-serial none' that +was being overridden by a following '-serial something' option, you +should delete the unnecessary '-serial none'. This will give you the +same behaviour as before, on QEMU versions both with and without this +bug fix. + +Cc: qemu-stable@nongnu.org +Reported-by: Bohdan Kostiv +Signed-off-by: Peter Maydell +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Richard Henderson +Message-id: 20240122163607.459769-2-peter.maydell@linaro.org +Fixes: 998bbd74b9d81 ("default devices: core code & serial lines") +Signed-off-by: Peter Maydell +(cherry picked from commit d2019a9d0c34a4fdcb5b5df550d73040dc0637d9) +Signed-off-by: Michael Tokarev +--- + system/vl.c | 22 +++++++++++++--------- + 1 file changed, 13 insertions(+), 9 deletions(-) + +diff --git a/system/vl.c b/system/vl.c +index 6b87bfa..938b7b5 100644 +--- a/system/vl.c ++++ b/system/vl.c +@@ -1440,18 +1440,22 @@ static void qemu_create_default_devices(void) + static int serial_parse(const char *devname) + { + int index = num_serial_hds; +- char label[32]; + +- if (strcmp(devname, "none") == 0) +- return 0; +- snprintf(label, sizeof(label), "serial%d", index); + serial_hds = g_renew(Chardev *, serial_hds, index + 1); + +- serial_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL); +- if (!serial_hds[index]) { +- error_report("could not connect serial device" +- " to character backend '%s'", devname); +- return -1; ++ if (strcmp(devname, "none") == 0) { ++ /* Don't allocate a serial device for this index */ ++ serial_hds[index] = NULL; ++ } else { ++ char label[32]; ++ snprintf(label, sizeof(label), "serial%d", index); ++ ++ serial_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL); ++ if (!serial_hds[index]) { ++ error_report("could not connect serial device" ++ " to character backend '%s'", devname); ++ return -1; ++ } + } + num_serial_hds++; + return 0; +-- +1.8.3.1 + diff --git a/0075-qemu-options.hx-Improve-serial-option-documentation.patch b/0075-qemu-options.hx-Improve-serial-option-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..bef94ad7b4d29e403d7a10c804090c7c44b4adca --- /dev/null +++ b/0075-qemu-options.hx-Improve-serial-option-documentation.patch @@ -0,0 +1,63 @@ +From 2d0530abe27bf5dce5aca269fbb2aa16e0ee88eb Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Mon, 22 Jan 2024 16:36:07 +0000 +Subject: [PATCH 081/293] qemu-options.hx: Improve -serial option documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The -serial option documentation is a bit brief about '-serial none' +and '-serial null'. In particular it's not very clear about the +difference between them, and it doesn't mention that it's up to +the machine model whether '-serial none' means "don't create the +serial port" or "don't wire the serial port up to anything". + +Expand on these points. + +Signed-off-by: Peter Maydell +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20240122163607.459769-3-peter.maydell@linaro.org +(cherry picked from commit 747bfaf3a9d2f3cd51674763dc1f7575100cd200) +Signed-off-by: Michael Tokarev +--- + qemu-options.hx | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/qemu-options.hx b/qemu-options.hx +index 42fd09e..b6b4ad9 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -4118,7 +4118,8 @@ SRST + This option can be used several times to simulate up to 4 serial + ports. + +- Use ``-serial none`` to disable all serial ports. ++ You can use ``-serial none`` to suppress the creation of default ++ serial devices. + + Available character devices are: + +@@ -4140,10 +4141,17 @@ SRST + [Linux only] Pseudo TTY (a new PTY is automatically allocated) + + ``none`` +- No device is allocated. ++ No device is allocated. Note that for machine types which ++ emulate systems where a serial device is always present in ++ real hardware, this may be equivalent to the ``null`` option, ++ in that the serial device is still present but all output ++ is discarded. For boards where the number of serial ports is ++ truly variable, this suppresses the creation of the device. + + ``null`` +- void device ++ A guest will see the UART or serial device as present in the ++ machine, but all output is discarded, and there is no input. ++ Conceptually equivalent to redirecting the output to ``/dev/null``. + + ``chardev:id`` + Use a named character device defined with the ``-chardev`` +-- +1.8.3.1 + diff --git a/0076-target-arm-Reinstate-vfp-property-on-AArch32-CPUs.patch b/0076-target-arm-Reinstate-vfp-property-on-AArch32-CPUs.patch new file mode 100644 index 0000000000000000000000000000000000000000..32fec8577bad54f29a2a65971c8692703a016873 --- /dev/null +++ b/0076-target-arm-Reinstate-vfp-property-on-AArch32-CPUs.patch @@ -0,0 +1,43 @@ +From de6992d390fa4e0623a135f0363b99cb6fd8ca5d Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 26 Jan 2024 19:34:32 +0000 +Subject: [PATCH 082/293] target/arm: Reinstate "vfp" property on AArch32 CPUs + +In commit 4315f7c614743 we restructured the logic for creating the +VFP related properties to avoid testing the aa32_simd_r32 feature on +AArch64 CPUs. However in the process we accidentally stopped +exposing the "vfp" QOM property on AArch32 TCG CPUs. + +This mostly hasn't had any ill effects because not many people want +to disable VFP, but it wasn't intentional. Reinstate the property. + +Cc: qemu-stable@nongnu.org +Fixes: 4315f7c614743 ("target/arm: Restructure has_vfp_d32 test") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2098 +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Message-id: 20240126193432.2210558-1-peter.maydell@linaro.org +(cherry picked from commit 185e3fdf8d106cb2f7d234d5e6453939c66db2a9) +Signed-off-by: Michael Tokarev +--- + target/arm/cpu.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index efb22a8..5d9bca5 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1615,6 +1615,10 @@ void arm_cpu_post_init(Object *obj) + } + } else if (cpu_isar_feature(aa32_vfp, cpu)) { + cpu->has_vfp = true; ++ if (tcg_enabled() || qtest_enabled()) { ++ qdev_property_add_static(DEVICE(obj), ++ &arm_cpu_has_vfp_property); ++ } + if (cpu_isar_feature(aa32_simd_r32, cpu)) { + cpu->has_vfp_d32 = true; + /* +-- +1.8.3.1 + diff --git a/0077-pci-host-designware-Limit-value-range-of-iATU-viewpo.patch b/0077-pci-host-designware-Limit-value-range-of-iATU-viewpo.patch new file mode 100644 index 0000000000000000000000000000000000000000..8a167e5bf5f80ee34c781f10708d4535c5bc5de5 --- /dev/null +++ b/0077-pci-host-designware-Limit-value-range-of-iATU-viewpo.patch @@ -0,0 +1,54 @@ +From 5f5e30229eea3971135ddc6dc70635866e605b63 Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Sun, 28 Jan 2024 22:00:55 -0800 +Subject: [PATCH 083/293] pci-host: designware: Limit value range of iATU + viewport register + +The latest version of qemu (v8.2.0-869-g7a1dc45af5) crashes when booting +the mcimx7d-sabre emulation with Linux v5.11 and later. + +qemu-system-arm: ../system/memory.c:2750: memory_region_set_alias_offset: Assertion `mr->alias' failed. + +Problem is that the Designware PCIe emulation accepts the full value range +for the iATU Viewport Register. However, both hardware and emulation only +support four inbound and four outbound viewports. + +The Linux kernel determines the number of supported viewports by writing +0xff into the viewport register and reading the value back. The expected +value when reading the register is the highest supported viewport index. +Match that code by masking the supported viewport value range when the +register is written. With this change, the Linux kernel reports + +imx6q-pcie 33800000.pcie: iATU: unroll F, 4 ob, 4 ib, align 0K, limit 4G + +as expected and supported. + +Fixes: d64e5eabc4c7 ("pci: Add support for Designware IP block") +Cc: Andrey Smirnov +Cc: Nikita Ostrenkov +Signed-off-by: Guenter Roeck +Message-id: 20240129060055.2616989-1-linux@roeck-us.net +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +(cherry picked from commit 8a73152020337a7fbf34daf0a006d4d89ec1494e) +Signed-off-by: Michael Tokarev +--- + hw/pci-host/designware.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c +index f477f97..f016f02 100644 +--- a/hw/pci-host/designware.c ++++ b/hw/pci-host/designware.c +@@ -340,6 +340,8 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address, + break; + + case DESIGNWARE_PCIE_ATU_VIEWPORT: ++ val &= DESIGNWARE_PCIE_ATU_REGION_INBOUND | ++ (DESIGNWARE_PCIE_NUM_VIEWPORTS - 1); + root->atu_viewport = val; + break; + +-- +1.8.3.1 + diff --git a/0078-tcg-loongarch64-Set-vector-registers-call-clobbered.patch b/0078-tcg-loongarch64-Set-vector-registers-call-clobbered.patch new file mode 100644 index 0000000000000000000000000000000000000000..22b355ac836db05fe69f08856d0d7d0662ea8dd1 --- /dev/null +++ b/0078-tcg-loongarch64-Set-vector-registers-call-clobbered.patch @@ -0,0 +1,39 @@ +From 8b7750c66f191ec830c2985dcc1382703b48a117 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 2 Feb 2024 09:34:14 +1000 +Subject: [PATCH 084/293] tcg/loongarch64: Set vector registers call clobbered + +Because there are more call clobbered registers than +call saved registers, we begin with all registers as +call clobbered and then reset those that are saved. + +This was missed when we introduced the LSX support. + +Cc: qemu-stable@nongnu.org +Fixes: 16288ded944 ("tcg/loongarch64: Lower basic tcg vec ops to LSX") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2136 +Signed-off-by: Richard Henderson +Reviewed-by: Song Gao +Message-Id: <20240201233414.500588-1-richard.henderson@linaro.org> +(cherry picked from commit 45bf0e7aa648369cf8ab2333bd20144806fc1be3) +Signed-off-by: Michael Tokarev +--- + tcg/loongarch64/tcg-target.c.inc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc +index bab0a17..dcf0205 100644 +--- a/tcg/loongarch64/tcg-target.c.inc ++++ b/tcg/loongarch64/tcg-target.c.inc +@@ -2327,7 +2327,7 @@ static void tcg_target_init(TCGContext *s) + tcg_target_available_regs[TCG_TYPE_I32] = ALL_GENERAL_REGS; + tcg_target_available_regs[TCG_TYPE_I64] = ALL_GENERAL_REGS; + +- tcg_target_call_clobber_regs = ALL_GENERAL_REGS; ++ tcg_target_call_clobber_regs = ALL_GENERAL_REGS | ALL_VECTOR_REGS; + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S0); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S1); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S2); +-- +1.8.3.1 + diff --git a/0079-hw-scsi-lsi53c895a-add-missing-decrement-of-reentran.patch b/0079-hw-scsi-lsi53c895a-add-missing-decrement-of-reentran.patch new file mode 100644 index 0000000000000000000000000000000000000000..4c31e812ccb4092b400a991377285693baea01eb --- /dev/null +++ b/0079-hw-scsi-lsi53c895a-add-missing-decrement-of-reentran.patch @@ -0,0 +1,41 @@ +From bbfcb0f7bcc1f905eee3997e56d42bb1e97de51d Mon Sep 17 00:00:00 2001 +From: Sven Schnelle +Date: Sun, 28 Jan 2024 21:22:14 +0100 +Subject: [PATCH 086/293] hw/scsi/lsi53c895a: add missing decrement of + reentrancy counter + +When the maximum count of SCRIPTS instructions is reached, the code +stops execution and returns, but fails to decrement the reentrancy +counter. This effectively renders the SCSI controller unusable +because on next entry the reentrancy counter is still above the limit. + +This bug was seen on HP-UX 10.20 which seems to trigger SCRIPTS +loops. + +Fixes: b987718bbb ("hw/scsi/lsi53c895a: Fix reentrancy issues in the LSI controller (CVE-2023-0330)") +Signed-off-by: Sven Schnelle +Message-ID: <20240128202214.2644768-1-svens@stackframe.org> +Reviewed-by: Thomas Huth +Tested-by: Helge Deller +Signed-off-by: Thomas Huth +(cherry picked from commit 8b09b7fe47082c69295a0fc0cc01b041b6385025) +Signed-off-by: Michael Tokarev +--- + hw/scsi/lsi53c895a.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c +index 634ed49..afbea0f 100644 +--- a/hw/scsi/lsi53c895a.c ++++ b/hw/scsi/lsi53c895a.c +@@ -1159,6 +1159,7 @@ again: + lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0); + lsi_disconnect(s); + trace_lsi_execute_script_stop(); ++ reentrancy_level--; + return; + } + insn = read_dword(s, s->dsp); +-- +1.8.3.1 + diff --git a/0080-iotests-fix-leak-of-tmpdir-in-dry-run-mode.patch b/0080-iotests-fix-leak-of-tmpdir-in-dry-run-mode.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1b4a9b75367e43dfd4d85e3b4ba13651b33ea90 --- /dev/null +++ b/0080-iotests-fix-leak-of-tmpdir-in-dry-run-mode.patch @@ -0,0 +1,45 @@ +From 88555e3607d322e46e1f33a2acf9a7f4055bfde9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Mon, 5 Feb 2024 15:40:19 +0000 +Subject: [PATCH 087/293] iotests: fix leak of tmpdir in dry-run mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Creating an instance of the 'TestEnv' class will create a temporary +directory. This dir is only deleted, however, in the __exit__ handler +invoked by a context manager. + +In dry-run mode, we don't use the TestEnv via a context manager, so +were leaking the temporary directory. Since meson invokes 'check' +5 times on each configure run, developers /tmp was filling up with +empty temporary directories. + +Signed-off-by: Daniel P. Berrangé +Message-ID: <20240205154019.1841037-1-berrange@redhat.com> +Reviewed-by: Michael Tokarev +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit c645bac4e06bf9642cc8e339d027a5d6ec54d811) +Signed-off-by: Michael Tokarev +--- + tests/qemu-iotests/check | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check +index f2e9d27..56d88ca 100755 +--- a/tests/qemu-iotests/check ++++ b/tests/qemu-iotests/check +@@ -184,7 +184,8 @@ if __name__ == '__main__': + sys.exit(str(e)) + + if args.dry_run: +- print('\n'.join([os.path.basename(t) for t in tests])) ++ with env: ++ print('\n'.join([os.path.basename(t) for t in tests])) + else: + with TestRunner(env, tap=args.tap, + color=args.color) as tr: +-- +1.8.3.1 + diff --git a/0081-iotests-give-tempdir-an-identifying-name.patch b/0081-iotests-give-tempdir-an-identifying-name.patch new file mode 100644 index 0000000000000000000000000000000000000000..dd7028fa0244452353e495052bcf9afb1ba42d70 --- /dev/null +++ b/0081-iotests-give-tempdir-an-identifying-name.patch @@ -0,0 +1,39 @@ +From 84c54eaeffd3caf83b0c105b904928b40bad5db9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Mon, 5 Feb 2024 15:51:58 +0000 +Subject: [PATCH 088/293] iotests: give tempdir an identifying name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If something goes wrong causing the iotests not to cleanup their +temporary directory, it is useful if the dir had an identifying +name to show what is to blame. + +Signed-off-by: Daniel P. Berrangé +Message-ID: <20240205155158.1843304-1-berrange@redhat.com> +Revieved-by: Michael Tokarev +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 7d2faf0ce2ccc896ac56bc5ed2cdf4a55056a8bb) +Signed-off-by: Michael Tokarev +--- + tests/qemu-iotests/testenv.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py +index 3ff38f2..588f30a 100644 +--- a/tests/qemu-iotests/testenv.py ++++ b/tests/qemu-iotests/testenv.py +@@ -126,7 +126,7 @@ def init_directories(self) -> None: + self.tmp_sock_dir = False + Path(self.sock_dir).mkdir(parents=True, exist_ok=True) + except KeyError: +- self.sock_dir = tempfile.mkdtemp() ++ self.sock_dir = tempfile.mkdtemp(prefix="qemu-iotests-") + self.tmp_sock_dir = True + + self.sample_img_dir = os.getenv('SAMPLE_IMG_DIR', +-- +1.8.3.1 + diff --git a/0082-virtio-scsi-Attach-event-vq-notifier-with-no_poll.patch b/0082-virtio-scsi-Attach-event-vq-notifier-with-no_poll.patch new file mode 100644 index 0000000000000000000000000000000000000000..f8c9387f71c1f94893b5baa9783be0c4b6030545 --- /dev/null +++ b/0082-virtio-scsi-Attach-event-vq-notifier-with-no_poll.patch @@ -0,0 +1,72 @@ +From feb2073c866fb2cd600c6783f196139120ff2f9e Mon Sep 17 00:00:00 2001 +From: Hanna Czenczek +Date: Fri, 2 Feb 2024 16:31:56 +0100 +Subject: [PATCH 089/293] virtio-scsi: Attach event vq notifier with no_poll + +As of commit 38738f7dbbda90fbc161757b7f4be35b52205552 ("virtio-scsi: +don't waste CPU polling the event virtqueue"), we only attach an io_read +notifier for the virtio-scsi event virtqueue instead, and no polling +notifiers. During operation, the event virtqueue is typically +non-empty, but none of the buffers are intended to be used immediately. +Instead, they only get used when certain events occur. Therefore, it +makes no sense to continuously poll it when non-empty, because it is +supposed to be and stay non-empty. + +We do this by using virtio_queue_aio_attach_host_notifier_no_poll() +instead of virtio_queue_aio_attach_host_notifier() for the event +virtqueue. + +Commit 766aa2de0f29b657148e04599320d771c36fd126 ("virtio-scsi: implement +BlockDevOps->drained_begin()") however has virtio_scsi_drained_end() use +virtio_queue_aio_attach_host_notifier() for all virtqueues, including +the event virtqueue. This can lead to it being polled again, undoing +the benefit of commit 38738f7dbbda90fbc161757b7f4be35b52205552. + +Fix it by using virtio_queue_aio_attach_host_notifier_no_poll() for the +event virtqueue. + +Reported-by: Fiona Ebner +Fixes: 766aa2de0f29b657148e04599320d771c36fd126 + ("virtio-scsi: implement BlockDevOps->drained_begin()") +Reviewed-by: Stefan Hajnoczi +Tested-by: Fiona Ebner +Reviewed-by: Fiona Ebner +Signed-off-by: Hanna Czenczek +Message-ID: <20240202153158.788922-2-hreitz@redhat.com> +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit c42c3833e0cfdf2b80fb3ca410acfd392b6874ab) +Signed-off-by: Michael Tokarev +--- + hw/scsi/virtio-scsi.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c +index 9c751bf..4b0d476 100644 +--- a/hw/scsi/virtio-scsi.c ++++ b/hw/scsi/virtio-scsi.c +@@ -1149,6 +1149,7 @@ static void virtio_scsi_drained_begin(SCSIBus *bus) + static void virtio_scsi_drained_end(SCSIBus *bus) + { + VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); ++ VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + VirtIODevice *vdev = VIRTIO_DEVICE(s); + uint32_t total_queues = VIRTIO_SCSI_VQ_NUM_FIXED + + s->parent_obj.conf.num_queues; +@@ -1166,7 +1167,11 @@ static void virtio_scsi_drained_end(SCSIBus *bus) + + for (uint32_t i = 0; i < total_queues; i++) { + VirtQueue *vq = virtio_get_queue(vdev, i); +- virtio_queue_aio_attach_host_notifier(vq, s->ctx); ++ if (vq == vs->event_vq) { ++ virtio_queue_aio_attach_host_notifier_no_poll(vq, s->ctx); ++ } else { ++ virtio_queue_aio_attach_host_notifier(vq, s->ctx); ++ } + } + } + +-- +1.8.3.1 + diff --git a/0083-virtio-Re-enable-notifications-after-drain.patch b/0083-virtio-Re-enable-notifications-after-drain.patch new file mode 100644 index 0000000000000000000000000000000000000000..65f3a7853709fddb7f27cd9afd4a7ce7a8a27a74 --- /dev/null +++ b/0083-virtio-Re-enable-notifications-after-drain.patch @@ -0,0 +1,133 @@ +From 00e50cb42941decc79b61be27a14d009f4d96695 Mon Sep 17 00:00:00 2001 +From: Hanna Czenczek +Date: Fri, 2 Feb 2024 16:31:57 +0100 +Subject: [PATCH 090/293] virtio: Re-enable notifications after drain + +During drain, we do not care about virtqueue notifications, which is why +we remove the handlers on it. When removing those handlers, whether vq +notifications are enabled or not depends on whether we were in polling +mode or not; if not, they are enabled (by default); if so, they have +been disabled by the io_poll_start callback. + +Because we do not care about those notifications after removing the +handlers, this is fine. However, we have to explicitly ensure they are +enabled when re-attaching the handlers, so we will resume receiving +notifications. We do this in virtio_queue_aio_attach_host_notifier*(). +If such a function is called while we are in a polling section, +attaching the notifiers will then invoke the io_poll_start callback, +re-disabling notifications. + +Because we will always miss virtqueue updates in the drained section, we +also need to poll the virtqueue once after attaching the notifiers. + +Buglink: https://issues.redhat.com/browse/RHEL-3934 +Signed-off-by: Hanna Czenczek +Message-ID: <20240202153158.788922-3-hreitz@redhat.com> +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 5bdbaebcce18fe6a627cafad2043ec08f3de5744) +Signed-off-by: Michael Tokarev +--- + hw/virtio/virtio.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + include/block/aio.h | 7 ++++++- + 2 files changed, 48 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 3a160f8..356d690 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -3556,6 +3556,17 @@ static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n) + + void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx) + { ++ /* ++ * virtio_queue_aio_detach_host_notifier() can leave notifications disabled. ++ * Re-enable them. (And if detach has not been used before, notifications ++ * being enabled is still the default state while a notifier is attached; ++ * see virtio_queue_host_notifier_aio_poll_end(), which will always leave ++ * notifications enabled once the polling section is left.) ++ */ ++ if (!virtio_queue_get_notification(vq)) { ++ virtio_queue_set_notification(vq, 1); ++ } ++ + aio_set_event_notifier(ctx, &vq->host_notifier, + virtio_queue_host_notifier_read, + virtio_queue_host_notifier_aio_poll, +@@ -3563,6 +3574,13 @@ void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx) + aio_set_event_notifier_poll(ctx, &vq->host_notifier, + virtio_queue_host_notifier_aio_poll_begin, + virtio_queue_host_notifier_aio_poll_end); ++ ++ /* ++ * We will have ignored notifications about new requests from the guest ++ * while no notifiers were attached, so "kick" the virt queue to process ++ * those requests now. ++ */ ++ event_notifier_set(&vq->host_notifier); + } + + /* +@@ -3573,14 +3591,38 @@ void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx) + */ + void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx) + { ++ /* See virtio_queue_aio_attach_host_notifier() */ ++ if (!virtio_queue_get_notification(vq)) { ++ virtio_queue_set_notification(vq, 1); ++ } ++ + aio_set_event_notifier(ctx, &vq->host_notifier, + virtio_queue_host_notifier_read, + NULL, NULL); ++ ++ /* ++ * See virtio_queue_aio_attach_host_notifier(). ++ * Note that this may be unnecessary for the type of virtqueues this ++ * function is used for. Still, it will not hurt to have a quick look into ++ * whether we can/should process any of the virtqueue elements. ++ */ ++ event_notifier_set(&vq->host_notifier); + } + + void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx) + { + aio_set_event_notifier(ctx, &vq->host_notifier, NULL, NULL, NULL); ++ ++ /* ++ * aio_set_event_notifier_poll() does not guarantee whether io_poll_end() ++ * will run after io_poll_begin(), so by removing the notifier, we do not ++ * know whether virtio_queue_host_notifier_aio_poll_end() has run after a ++ * previous virtio_queue_host_notifier_aio_poll_begin(), i.e. whether ++ * notifications are enabled or disabled. It does not really matter anyway; ++ * we just removed the notifier, so we do not care about notifications until ++ * we potentially re-attach it. The attach_host_notifier functions will ++ * ensure that notifications are enabled again when they are needed. ++ */ + } + + void virtio_queue_host_notifier_read(EventNotifier *n) +diff --git a/include/block/aio.h b/include/block/aio.h +index f08b358..795a375 100644 +--- a/include/block/aio.h ++++ b/include/block/aio.h +@@ -497,9 +497,14 @@ void aio_set_event_notifier(AioContext *ctx, + AioPollFn *io_poll, + EventNotifierHandler *io_poll_ready); + +-/* Set polling begin/end callbacks for an event notifier that has already been ++/* ++ * Set polling begin/end callbacks for an event notifier that has already been + * registered with aio_set_event_notifier. Do nothing if the event notifier is + * not registered. ++ * ++ * Note that if the io_poll_end() callback (or the entire notifier) is removed ++ * during polling, it will not be called, so an io_poll_begin() is not ++ * necessarily always followed by an io_poll_end(). + */ + void aio_set_event_notifier_poll(AioContext *ctx, + EventNotifier *notifier, +-- +1.8.3.1 + diff --git a/0084-virtio-blk-avoid-using-ioeventfd-state-in-irqfd-cond.patch b/0084-virtio-blk-avoid-using-ioeventfd-state-in-irqfd-cond.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ab3f39c95f3132a506101d2634e67410f08b51f --- /dev/null +++ b/0084-virtio-blk-avoid-using-ioeventfd-state-in-irqfd-cond.patch @@ -0,0 +1,67 @@ +From c36d4d3ceeb2c197614d552fc1aab5551d7d57f9 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Mon, 22 Jan 2024 12:26:25 -0500 +Subject: [PATCH 091/293] virtio-blk: avoid using ioeventfd state in irqfd + conditional + +Requests that complete in an IOThread use irqfd to notify the guest +while requests that complete in the main loop thread use the traditional +qdev irq code path. The reason for this conditional is that the irq code +path requires the BQL: + + if (s->ioeventfd_started && !s->ioeventfd_disabled) { + virtio_notify_irqfd(vdev, req->vq); + } else { + virtio_notify(vdev, req->vq); + } + +There is a corner case where the conditional invokes the irq code path +instead of the irqfd code path: + + static void virtio_blk_stop_ioeventfd(VirtIODevice *vdev) + { + ... + /* + * Set ->ioeventfd_started to false before draining so that host notifiers + * are not detached/attached anymore. + */ + s->ioeventfd_started = false; + + /* Wait for virtio_blk_dma_restart_bh() and in flight I/O to complete */ + blk_drain(s->conf.conf.blk); + +During blk_drain() the conditional produces the wrong result because +ioeventfd_started is false. + +Use qemu_in_iothread() instead of checking the ioeventfd state. + +Cc: qemu-stable@nongnu.org +Buglink: https://issues.redhat.com/browse/RHEL-15394 +Signed-off-by: Stefan Hajnoczi +Message-ID: <20240122172625.415386-1-stefanha@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit bfa36802d1704fc413c590ebdcc4e5ae0eacf439) +Signed-off-by: Michael Tokarev +(Mjt: fixup for v8.2.0-809-g3cdaf3dd4a + "virtio-blk: rename dataplane to ioeventfd") +--- + hw/block/virtio-blk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c +index a1f8e15..31aac14 100644 +--- a/hw/block/virtio-blk.c ++++ b/hw/block/virtio-blk.c +@@ -65,7 +65,7 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) + iov_discard_undo(&req->inhdr_undo); + iov_discard_undo(&req->outhdr_undo); + virtqueue_push(req->vq, &req->elem, req->in_len); +- if (s->dataplane_started && !s->dataplane_disabled) { ++ if (qemu_in_iothread()) { + virtio_blk_data_plane_notify(s->dataplane, req->vq); + } else { + virtio_notify(vdev, req->vq); +-- +1.8.3.1 + diff --git a/0085-migration-Fix-logic-of-channels-and-transport-compat.patch b/0085-migration-Fix-logic-of-channels-and-transport-compat.patch new file mode 100644 index 0000000000000000000000000000000000000000..9c33a813e8e52462f23121f5d59054db54ce6ae4 --- /dev/null +++ b/0085-migration-Fix-logic-of-channels-and-transport-compat.patch @@ -0,0 +1,71 @@ +From 76c172ffbe931c5018bd781fa565327010068b16 Mon Sep 17 00:00:00 2001 +From: Avihai Horon +Date: Thu, 25 Jan 2024 18:25:12 +0200 +Subject: [PATCH 092/293] migration: Fix logic of channels and transport + compatibility check + +The commit in the fixes line mistakenly modified the channels and +transport compatibility check logic so it now checks multi-channel +support only for socket transport type. + +Thus, running multifd migration using a transport other than socket that +is incompatible with multi-channels (such as "exec") would lead to a +segmentation fault instead of an error message. +For example: + (qemu) migrate_set_capability multifd on + (qemu) migrate -d "exec:cat > /tmp/vm_state" + Segmentation fault (core dumped) + +Fix it by checking multi-channel compatibility for all transport types. + +Cc: qemu-stable +Fixes: d95533e1cdcc ("migration: modify migration_channels_and_uri_compatible() for new QAPI syntax") +Signed-off-by: Avihai Horon +Reviewed-by: Peter Xu +Link: https://lore.kernel.org/r/20240125162528.7552-2-avihaih@nvidia.com +Signed-off-by: Peter Xu +(cherry picked from commit 3205bebd4fc6dd501fb8b10c93ddce9da18e09db) +Signed-off-by: Michael Tokarev +--- + migration/migration.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index ee5e0ba..982ab85 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -128,11 +128,17 @@ static bool migration_needs_multiple_sockets(void) + return migrate_multifd() || migrate_postcopy_preempt(); + } + +-static bool transport_supports_multi_channels(SocketAddress *saddr) ++static bool transport_supports_multi_channels(MigrationAddress *addr) + { +- return saddr->type == SOCKET_ADDRESS_TYPE_INET || +- saddr->type == SOCKET_ADDRESS_TYPE_UNIX || +- saddr->type == SOCKET_ADDRESS_TYPE_VSOCK; ++ if (addr->transport == MIGRATION_ADDRESS_TYPE_SOCKET) { ++ SocketAddress *saddr = &addr->u.socket; ++ ++ return saddr->type == SOCKET_ADDRESS_TYPE_INET || ++ saddr->type == SOCKET_ADDRESS_TYPE_UNIX || ++ saddr->type == SOCKET_ADDRESS_TYPE_VSOCK; ++ } ++ ++ return false; + } + + static bool +@@ -140,8 +146,7 @@ migration_channels_and_transport_compatible(MigrationAddress *addr, + Error **errp) + { + if (migration_needs_multiple_sockets() && +- (addr->transport == MIGRATION_ADDRESS_TYPE_SOCKET) && +- !transport_supports_multi_channels(&addr->u.socket)) { ++ !transport_supports_multi_channels(addr)) { + error_setg(errp, "Migration requires multi-channel URIs (e.g. tcp)"); + return false; + } +-- +1.8.3.1 + diff --git a/0086-hw-riscv-virt-acpi-build.c-fix-leak-in-build_rhct.patch b/0086-hw-riscv-virt-acpi-build.c-fix-leak-in-build_rhct.patch new file mode 100644 index 0000000000000000000000000000000000000000..ff0eb199cdefe27958d997beb305ff9a04bded0d --- /dev/null +++ b/0086-hw-riscv-virt-acpi-build.c-fix-leak-in-build_rhct.patch @@ -0,0 +1,54 @@ +From eca4e19914baba9fd73f774eb517acdd80add813 Mon Sep 17 00:00:00 2001 +From: Daniel Henrique Barboza +Date: Mon, 22 Jan 2024 19:15:23 -0300 +Subject: [PATCH 093/293] hw/riscv/virt-acpi-build.c: fix leak in build_rhct() + +The 'isa' char pointer isn't being freed after use. + +Issue detected by Valgrind: + +==38752== 128 bytes in 1 blocks are definitely lost in loss record 3,190 of 3,884 +==38752== at 0x484280F: malloc (vg_replace_malloc.c:442) +==38752== by 0x5189619: g_malloc (gmem.c:130) +==38752== by 0x51A5BF2: g_strconcat (gstrfuncs.c:628) +==38752== by 0x6C1E3E: riscv_isa_string_ext (cpu.c:2321) +==38752== by 0x6C1E3E: riscv_isa_string (cpu.c:2343) +==38752== by 0x6BD2EA: build_rhct (virt-acpi-build.c:232) +==38752== by 0x6BD2EA: virt_acpi_build (virt-acpi-build.c:556) +==38752== by 0x6BDC86: virt_acpi_setup (virt-acpi-build.c:662) +==38752== by 0x9C8DC6: notifier_list_notify (notify.c:39) +==38752== by 0x4A595A: qdev_machine_creation_done (machine.c:1589) +==38752== by 0x61E052: qemu_machine_creation_done (vl.c:2680) +==38752== by 0x61E052: qmp_x_exit_preconfig.part.0 (vl.c:2709) +==38752== by 0x6220C6: qmp_x_exit_preconfig (vl.c:2702) +==38752== by 0x6220C6: qemu_init (vl.c:3758) +==38752== by 0x425858: main (main.c:47) + +Fixes: ebfd392893 ("hw/riscv/virt: virt-acpi-build.c: Add RHCT Table") +Signed-off-by: Daniel Henrique Barboza +Reviewed-by: Alistair Francis +Message-ID: <20240122221529.86562-2-dbarboza@ventanamicro.com> +Signed-off-by: Alistair Francis +(cherry picked from commit 1a49762c07d001ce291e4fc6773317f5611af3a4) +Signed-off-by: Michael Tokarev +(Mjt: context fixup) +--- + hw/riscv/virt-acpi-build.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index 7331248..171d56a 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -132,7 +132,7 @@ static void build_rhct(GArray *table_data, + size_t len, aligned_len; + uint32_t isa_offset, num_rhct_nodes; + RISCVCPU *cpu; +- char *isa; ++ g_autofree char *isa = NULL; + + AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id, + .oem_table_id = s->oem_table_id }; +-- +1.8.3.1 + diff --git a/0087-tests-docker-Add-sqlite3-module-to-openSUSE-Leap-con.patch b/0087-tests-docker-Add-sqlite3-module-to-openSUSE-Leap-con.patch new file mode 100644 index 0000000000000000000000000000000000000000..a3721358b267a130e8467be14988d684fecd2b30 --- /dev/null +++ b/0087-tests-docker-Add-sqlite3-module-to-openSUSE-Leap-con.patch @@ -0,0 +1,80 @@ +From cefca32a2440ffc7bfb247b064d713d9de7c4489 Mon Sep 17 00:00:00 2001 +From: Fabiano Rosas +Date: Wed, 7 Feb 2024 16:37:59 +0000 +Subject: [PATCH 094/293] tests/docker: Add sqlite3 module to openSUSE Leap + container +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Avocado needs sqlite3: + + Failed to load plugin from module "avocado.plugins.journal": + ImportError("Module 'sqlite3' is not installed. + Use: sudo zypper install python311 to install it") + +>From 'zypper info python311': + "This package supplies rich command line features provided by + readline, and sqlite3 support for the interpreter core, thus forming + a so called "extended" runtime." + +Include the appropriate package in the lcitool mappings which will +guarantee the dockerfile gets properly updated when lcitool is +run. Also include the updated dockerfile. + +Signed-off-by: Fabiano Rosas +Suggested-by: Andrea Bolognani +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20240117164227.32143-1-farosas@suse.de> +Signed-off-by: Alex Bennée +Message-Id: <20240207163812.3231697-2-alex.bennee@linaro.org> +(cherry picked from commit 7485508341f4e8c6802f7716a64dd49a4dd28d22) +Signed-off-by: Michael Tokarev +--- + tests/docker/dockerfiles/opensuse-leap.docker | 1 + + tests/lcitool/mappings.yml | 4 ++++ + tests/lcitool/projects/qemu.yml | 1 + + 3 files changed, 6 insertions(+) + +diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker +index dc0e36c..cf75338 100644 +--- a/tests/docker/dockerfiles/opensuse-leap.docker ++++ b/tests/docker/dockerfiles/opensuse-leap.docker +@@ -90,6 +90,7 @@ RUN zypper update -y && \ + pcre-devel-static \ + pipewire-devel \ + pkgconfig \ ++ python311 \ + python311-base \ + python311-pip \ + python311-setuptools \ +diff --git a/tests/lcitool/mappings.yml b/tests/lcitool/mappings.yml +index 0b90888..407c033 100644 +--- a/tests/lcitool/mappings.yml ++++ b/tests/lcitool/mappings.yml +@@ -59,6 +59,10 @@ mappings: + CentOSStream8: + OpenSUSELeap15: + ++ python3-sqlite3: ++ CentOSStream8: python38 ++ OpenSUSELeap15: python311 ++ + python3-tomli: + # test using tomllib + apk: +diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml +index 82092c9..149b15d 100644 +--- a/tests/lcitool/projects/qemu.yml ++++ b/tests/lcitool/projects/qemu.yml +@@ -97,6 +97,7 @@ packages: + - python3-pip + - python3-sphinx + - python3-sphinx-rtd-theme ++ - python3-sqlite3 + - python3-tomli + - python3-venv + - rpm2cpio +-- +1.8.3.1 + diff --git a/0088-configure-run-plugin-TCG-tests-again.patch b/0088-configure-run-plugin-TCG-tests-again.patch new file mode 100644 index 0000000000000000000000000000000000000000..6921c42c4438a7e7621174376e0ae19f78e76c17 --- /dev/null +++ b/0088-configure-run-plugin-TCG-tests-again.patch @@ -0,0 +1,46 @@ +From 6eeeb8733177db7bc23fb2e7271dea759b47e4f9 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 7 Feb 2024 16:38:01 +0000 +Subject: [PATCH 095/293] configure: run plugin TCG tests again +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 39fb3cfc28b ("configure: clean up plugin option handling", 2023-10-18) +dropped the CONFIG_PLUGIN line from tests/tcg/config-host.mak, due to confusion +caused by the shadowing of $config_host_mak. However, TCG tests were still +expecting it. Oops. + +Put it back, in the meanwhile the shadowing is gone so it's clear that it goes +in the tests/tcg configuration. + +Cc: +Fixes: 39fb3cfc28b ("configure: clean up plugin option handling", 2023-10-18) +Signed-off-by: Paolo Bonzini +Message-Id: <20240124115332.612162-1-pbonzini@redhat.com> +Signed-off-by: Alex Bennée +Message-Id: <20240207163812.3231697-4-alex.bennee@linaro.org> +(cherry picked from commit 15cc103362499bd94c5aec5fa66543d0de3bf4b5) +Signed-off-by: Michael Tokarev +(Mjt: context fixup) +--- + configure | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/configure b/configure +index d7e0926..d3ab436 100755 +--- a/configure ++++ b/configure +@@ -1675,6 +1675,9 @@ fi + mkdir -p tests/tcg + echo "# Automatically generated by configure - do not modify" > $config_host_mak + echo "SRC_PATH=$source_path" >> $config_host_mak ++if test "$plugins" = "yes" ; then ++ echo "CONFIG_PLUGIN=y" >> tests/tcg/$config_host_mak ++fi + + tcg_tests_targets= + for target in $target_list; do +-- +1.8.3.1 + diff --git a/0089-hw-smbios-Fix-OEM-strings-table-option-validation.patch b/0089-hw-smbios-Fix-OEM-strings-table-option-validation.patch new file mode 100644 index 0000000000000000000000000000000000000000..04011f127a9d08d83fcfa5c4f659552c3b94267f --- /dev/null +++ b/0089-hw-smbios-Fix-OEM-strings-table-option-validation.patch @@ -0,0 +1,48 @@ +From d6e07d59169e16beba99fd139d1fb99ca197c555 Mon Sep 17 00:00:00 2001 +From: Akihiko Odaki +Date: Mon, 29 Jan 2024 17:03:07 +0900 +Subject: [PATCH 096/293] hw/smbios: Fix OEM strings table option validation + +qemu_smbios_type11_opts did not have the list terminator and that +resulted in out-of-bound memory access. It also needs to have an element +for the type option. + +Cc: qemu-stable@nongnu.org +Fixes: 2d6dcbf93fb0 ("smbios: support setting OEM strings table") +Signed-off-by: Akihiko Odaki +Reviewed-by: Michael Tokarev +Reviewed-by: Ani Sinha +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael Tokarev +(cherry picked from commit cd8a35b913c24248267c682cb9a348461c106139) +--- + hw/smbios/smbios.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c +index 2a90601..522ed1e 100644 +--- a/hw/smbios/smbios.c ++++ b/hw/smbios/smbios.c +@@ -370,6 +370,11 @@ static const QemuOptDesc qemu_smbios_type8_opts[] = { + + static const QemuOptDesc qemu_smbios_type11_opts[] = { + { ++ .name = "type", ++ .type = QEMU_OPT_NUMBER, ++ .help = "SMBIOS element type", ++ }, ++ { + .name = "value", + .type = QEMU_OPT_STRING, + .help = "OEM string data", +@@ -379,6 +384,7 @@ static const QemuOptDesc qemu_smbios_type11_opts[] = { + .type = QEMU_OPT_STRING, + .help = "OEM string data from file", + }, ++ { /* end of list */ } + }; + + static const QemuOptDesc qemu_smbios_type17_opts[] = { +-- +1.8.3.1 + diff --git a/0090-hw-smbios-Fix-port-connector-option-validation.patch b/0090-hw-smbios-Fix-port-connector-option-validation.patch new file mode 100644 index 0000000000000000000000000000000000000000..146b798d4a2686e39d76c3367084e380681acd36 --- /dev/null +++ b/0090-hw-smbios-Fix-port-connector-option-validation.patch @@ -0,0 +1,48 @@ +From 9ab476c3de1c2ff5851f00671cd24d6a16efff54 Mon Sep 17 00:00:00 2001 +From: Akihiko Odaki +Date: Mon, 29 Jan 2024 17:03:08 +0900 +Subject: [PATCH 097/293] hw/smbios: Fix port connector option validation + +qemu_smbios_type8_opts did not have the list terminator and that +resulted in out-of-bound memory access. It also needs to have an element +for the type option. + +Cc: qemu-stable@nongnu.org +Fixes: fd8caa253c56 ("hw/smbios: support for type 8 (port connector)") +Signed-off-by: Akihiko Odaki +Reviewed-by: Michael Tokarev +Reviewed-by: Ani Sinha +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael Tokarev +(cherry picked from commit 196578c9d051d19c23e6c13e97b791a41b318315) +--- + hw/smbios/smbios.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c +index 522ed1e..8a44d3f 100644 +--- a/hw/smbios/smbios.c ++++ b/hw/smbios/smbios.c +@@ -347,6 +347,11 @@ static const QemuOptDesc qemu_smbios_type4_opts[] = { + + static const QemuOptDesc qemu_smbios_type8_opts[] = { + { ++ .name = "type", ++ .type = QEMU_OPT_NUMBER, ++ .help = "SMBIOS element type", ++ }, ++ { + .name = "internal_reference", + .type = QEMU_OPT_STRING, + .help = "internal reference designator", +@@ -366,6 +371,7 @@ static const QemuOptDesc qemu_smbios_type8_opts[] = { + .type = QEMU_OPT_NUMBER, + .help = "port type", + }, ++ { /* end of list */ } + }; + + static const QemuOptDesc qemu_smbios_type11_opts[] = { +-- +1.8.3.1 + diff --git a/0091-hw-net-tulip-add-chip-status-register-values.patch b/0091-hw-net-tulip-add-chip-status-register-values.patch new file mode 100644 index 0000000000000000000000000000000000000000..3c25a670a9c464b4d351216fbc589269d70f84f6 --- /dev/null +++ b/0091-hw-net-tulip-add-chip-status-register-values.patch @@ -0,0 +1,56 @@ +From 281fea01d6d71ea8f5b33390f32886f054813cf6 Mon Sep 17 00:00:00 2001 +From: Sven Schnelle +Date: Mon, 5 Feb 2024 20:47:17 +0100 +Subject: [PATCH 098/293] hw/net/tulip: add chip status register values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Netbsd isn't able to detect a link on the emulated tulip card. That's +because netbsd reads the Chip Status Register of the Phy (address +0x14). The default phy data in the qemu tulip driver is all zero, +which means no link is established and autonegotation isn't complete. + +Therefore set the register to 0x3b40, which means: + +Link is up, Autonegotation complete, Full Duplex, 100MBit/s Link +speed. + +Also clear the mask because this register is read only. + +Signed-off-by: Sven Schnelle +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Helge Deller +Tested-by: Helge Deller +Signed-off-by: Helge Deller +(cherry picked from commit 9b60a3ed5569a70bbdd29e3c9ec4c5d4685c6e2c) +Signed-off-by: Michael Tokarev +--- + hw/net/tulip.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/net/tulip.c b/hw/net/tulip.c +index 962086a..f21b8ca 100644 +--- a/hw/net/tulip.c ++++ b/hw/net/tulip.c +@@ -421,7 +421,7 @@ static uint16_t tulip_mdi_default[] = { + /* MDI Registers 8 - 15 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* MDI Registers 16 - 31 */ +- 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0003, 0x0000, 0x0001, 0x0000, 0x3b40, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + }; + +@@ -429,7 +429,7 @@ static uint16_t tulip_mdi_default[] = { + static const uint16_t tulip_mdi_mask[] = { + 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +- 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, ++ 0x0fff, 0x0000, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + }; + +-- +1.8.3.1 + diff --git a/0092-tcg-Increase-width-of-temp_subindex.patch b/0092-tcg-Increase-width-of-temp_subindex.patch new file mode 100644 index 0000000000000000000000000000000000000000..0db98ddd611e94cee8b0344abc6a46e9f837bc98 --- /dev/null +++ b/0092-tcg-Increase-width-of-temp_subindex.patch @@ -0,0 +1,39 @@ +From e5f105655c226262d9d7529dc8ee70402d9ef4ad Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Mon, 12 Feb 2024 16:15:59 -1000 +Subject: [PATCH 099/293] tcg: Increase width of temp_subindex +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We need values 0-3 for TCG_TYPE_I128 on 32-bit hosts. + +Cc: qemu-stable@nongnu.org +Fixes: 43eef72f4109 ("tcg: Add temp allocation for TCGv_i128") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2159 +Signed-off-by: Richard Henderson +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Michael Tokarev +Tested-by: Michael Tokarev +(cherry picked from commit c0e688153f299d5d493989c80bcc84c9cf36d6a6) +Signed-off-by: Michael Tokarev +--- + include/tcg/tcg.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h +index daf2a5b..451f3fe 100644 +--- a/include/tcg/tcg.h ++++ b/include/tcg/tcg.h +@@ -412,7 +412,7 @@ typedef struct TCGTemp { + unsigned int mem_coherent:1; + unsigned int mem_allocated:1; + unsigned int temp_allocated:1; +- unsigned int temp_subindex:1; ++ unsigned int temp_subindex:2; + + int64_t val; + struct TCGTemp *mem_base; +-- +1.8.3.1 + diff --git a/0093-tcg-arm-Fix-goto_tb-for-large-translation-blocks.patch b/0093-tcg-arm-Fix-goto_tb-for-large-translation-blocks.patch new file mode 100644 index 0000000000000000000000000000000000000000..a1551f22ed3840c1f2e39fcfb6041f1457e5cc81 --- /dev/null +++ b/0093-tcg-arm-Fix-goto_tb-for-large-translation-blocks.patch @@ -0,0 +1,38 @@ +From 181e54871574bf5aa10b5a44fec94f198bc912ce Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Mon, 12 Feb 2024 20:38:18 +0000 +Subject: [PATCH 100/293] tcg/arm: Fix goto_tb for large translation blocks + +Correct arithmetic for separating high and low +on a large negative number. + +Cc: qemu-stable@nongnu.org +Fixes: 79ffece4447 ("tcg/arm: Implement direct branch for goto_tb") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1714 +Signed-off-by: Richard Henderson +Reviewed-by: Michael Tokarev +(cherry picked from commit e41f1825b43796c3508ef309ed0b150ef89acc44) +Signed-off-by: Michael Tokarev +--- + tcg/arm/tcg-target.c.inc | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc +index a9aa8aa..c9a47b7 100644 +--- a/tcg/arm/tcg-target.c.inc ++++ b/tcg/arm/tcg-target.c.inc +@@ -1736,9 +1736,9 @@ static void tcg_out_goto_tb(TCGContext *s, int which) + * shifted immediate from pc. + */ + int h = -i_disp; +- int l = h & 0xfff; ++ int l = -(h & 0xfff); + +- h = encode_imm_nofail(h - l); ++ h = encode_imm_nofail(h + l); + tcg_out_dat_imm(s, COND_AL, ARITH_SUB, TCG_REG_R0, TCG_REG_PC, h); + tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, l); + } +-- +1.8.3.1 + diff --git a/0094-vhost-user.rst-Fix-vring-address-description.patch b/0094-vhost-user.rst-Fix-vring-address-description.patch new file mode 100644 index 0000000000000000000000000000000000000000..d908db3a533df4a82f4ae113fa214a22f91628dd --- /dev/null +++ b/0094-vhost-user.rst-Fix-vring-address-description.patch @@ -0,0 +1,38 @@ +From 17ae7ebedcbd958c03a0878ff92d970ebca123c6 Mon Sep 17 00:00:00 2001 +From: Andrey Ignatov +Date: Thu, 11 Jan 2024 16:45:55 -0800 +Subject: [PATCH 101/293] vhost-user.rst: Fix vring address description + +There is no "size" field in vring address structure. Remove it. + +Fixes: 5fc0e00291 ("Add vhost-user protocol documentation") +Signed-off-by: Andrey Ignatov +Message-Id: <20240112004555.64900-1-rdna@apple.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit aa05bd9ef4073ccb72d04ad78de32916af31c7c3) +Signed-off-by: Michael Tokarev +--- + docs/interop/vhost-user.rst | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst +index 9f1103f..ad6e142 100644 +--- a/docs/interop/vhost-user.rst ++++ b/docs/interop/vhost-user.rst +@@ -148,9 +148,9 @@ Vring descriptor indices for packed virtqueues + A vring address description + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +-+-------+-------+------+------------+------+-----------+-----+ +-| index | flags | size | descriptor | used | available | log | +-+-------+-------+------+------------+------+-----------+-----+ +++-------+-------+------------+------+-----------+-----+ ++| index | flags | descriptor | used | available | log | +++-------+-------+------------+------+-----------+-----+ + + :index: a 32-bit vring index + +-- +1.8.3.1 + diff --git a/0095-cxl-cdat-Handle-cdat-table-build-errors.patch b/0095-cxl-cdat-Handle-cdat-table-build-errors.patch new file mode 100644 index 0000000000000000000000000000000000000000..58679e226ee5c13a07e09a9e3b9267a07935c145 --- /dev/null +++ b/0095-cxl-cdat-Handle-cdat-table-build-errors.patch @@ -0,0 +1,42 @@ +From 89970831184893c21edcf455e0d91aaedd27a02d Mon Sep 17 00:00:00 2001 +From: Ira Weiny +Date: Fri, 26 Jan 2024 12:01:21 +0000 +Subject: [PATCH 102/293] cxl/cdat: Handle cdat table build errors + +The callback for building CDAT tables may return negative error codes. +This was previously unhandled and will result in potentially huge +allocations later on in ct3_build_cdat() + +Detect the negative error code and defer cdat building. + +Fixes: f5ee7413d592 ("hw/mem/cxl-type3: Add CXL CDAT Data Object Exchange") +Cc: Huai-Cheng Kuo +Reviewed-by: Dave Jiang +Reviewed-by: Fan Ni +Signed-off-by: Ira Weiny +Signed-off-by: Jonathan Cameron +Message-Id: <20240126120132.24248-2-Jonathan.Cameron@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit c62926f730d08450502d36548e28dd727c998ace) +Signed-off-by: Michael Tokarev +--- + hw/cxl/cxl-cdat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/cxl/cxl-cdat.c b/hw/cxl/cxl-cdat.c +index 639a2db..24829cf 100644 +--- a/hw/cxl/cxl-cdat.c ++++ b/hw/cxl/cxl-cdat.c +@@ -63,7 +63,7 @@ static void ct3_build_cdat(CDATObject *cdat, Error **errp) + cdat->built_buf_len = cdat->build_cdat_table(&cdat->built_buf, + cdat->private); + +- if (!cdat->built_buf_len) { ++ if (cdat->built_buf_len <= 0) { + /* Build later as not all data available yet */ + cdat->to_update = true; + return; +-- +1.8.3.1 + diff --git a/0096-cxl-cdat-Fix-header-sum-value-in-CDAT-checksum.patch b/0096-cxl-cdat-Fix-header-sum-value-in-CDAT-checksum.patch new file mode 100644 index 0000000000000000000000000000000000000000..ed411a6d2ec6c9643e2608063b760b34f8f2a68e --- /dev/null +++ b/0096-cxl-cdat-Fix-header-sum-value-in-CDAT-checksum.patch @@ -0,0 +1,63 @@ +From 9d8a2a8aafa575429ccb001c99827ea199fbe7a6 Mon Sep 17 00:00:00 2001 +From: Ira Weiny +Date: Fri, 26 Jan 2024 12:01:24 +0000 +Subject: [PATCH 103/293] cxl/cdat: Fix header sum value in CDAT checksum + +The addition of the DCD support for CXL type-3 devices extended the CDAT +table large enough that the checksum being returned was incorrect.[1] + +This was because the checksum value was using the header length field +rather than each of the 4 bytes of the length field. This was +previously not seen because the length of the CDAT data was less than +256 thus resulting in an equivalent checksum value. + +Properly calculate the checksum for the CDAT header. + +[1] https://lore.kernel.org/all/20231116-fix-cdat-devm-free-v1-1-b148b40707d7@intel.com/ + +Fixes: aba578bdace5 ("hw/cxl/cdat: CXL CDAT Data Object Exchange implementation") +Cc: Huai-Cheng Kuo +Signed-off-by: Ira Weiny +Reviewed-by: Dave Jiang +Reviewed-by: Fan Ni +Signed-off-by: Jonathan Cameron + +Message-Id: <20240126120132.24248-5-Jonathan.Cameron@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 64fdad5e67587e88c2f1d8f294e89403856a4a31) +Signed-off-by: Michael Tokarev +--- + hw/cxl/cxl-cdat.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/hw/cxl/cxl-cdat.c b/hw/cxl/cxl-cdat.c +index 24829cf..2fea975 100644 +--- a/hw/cxl/cxl-cdat.c ++++ b/hw/cxl/cxl-cdat.c +@@ -49,6 +49,7 @@ static void ct3_build_cdat(CDATObject *cdat, Error **errp) + g_autofree CDATTableHeader *cdat_header = NULL; + g_autofree CDATEntry *cdat_st = NULL; + uint8_t sum = 0; ++ uint8_t *hdr_buf; + int ent, i; + + /* Use default table if fopen == NULL */ +@@ -95,8 +96,12 @@ static void ct3_build_cdat(CDATObject *cdat, Error **errp) + /* For now, no runtime updates */ + cdat_header->sequence = 0; + cdat_header->length += sizeof(CDATTableHeader); +- sum += cdat_header->revision + cdat_header->sequence + +- cdat_header->length; ++ ++ hdr_buf = (uint8_t *)cdat_header; ++ for (i = 0; i < sizeof(*cdat_header); i++) { ++ sum += hdr_buf[i]; ++ } ++ + /* Sum of all bytes including checksum must be 0 */ + cdat_header->checksum = ~sum + 1; + +-- +1.8.3.1 + diff --git a/0097-hw-cxl-device-read-from-register-values-in-mdev_reg_.patch b/0097-hw-cxl-device-read-from-register-values-in-mdev_reg_.patch new file mode 100644 index 0000000000000000000000000000000000000000..e36adab64e2cf9c2512b6535fae70ce054992514 --- /dev/null +++ b/0097-hw-cxl-device-read-from-register-values-in-mdev_reg_.patch @@ -0,0 +1,105 @@ +From bdd3159ad724e4e0aad571b4352b288b8f947ddd Mon Sep 17 00:00:00 2001 +From: Hyeonggon Yoo <42.hyeyoo@gmail.com> +Date: Fri, 26 Jan 2024 12:01:26 +0000 +Subject: [PATCH 104/293] hw/cxl/device: read from register values in + mdev_reg_read() + +In the current mdev_reg_read() implementation, it consistently returns +that the Media Status is Ready (01b). This was fine until commit +25a52959f99d ("hw/cxl: Add support for device sanitation") because the +media was presumed to be ready. + +However, as per the CXL 3.0 spec "8.2.9.8.5.1 Sanitize (Opcode 4400h)", +during sanitation, the Media State should be set to Disabled (11b). The +mentioned commit correctly sets it to Disabled, but mdev_reg_read() +still returns Media Status as Ready. + +To address this, update mdev_reg_read() to read register values instead +of returning dummy values. + +Note that __toggle_media() managed to not only write something +that no one read, it did it to the wrong register storage and +so changed the reported mailbox size which was definitely not +the intent. That gets fixed as a side effect of allocating +separate state storage for this register. + +Fixes: commit 25a52959f99d ("hw/cxl: Add support for device sanitation") +Signed-off-by: Hyeonggon Yoo <42.hyeyoo@gmail.com> +Reviewed-by: Fan Ni +Signed-off-by: Jonathan Cameron +Message-Id: <20240126120132.24248-7-Jonathan.Cameron@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit f7509f462c788a347521f90f19d623908c4fbcc5) +Signed-off-by: Michael Tokarev +--- + hw/cxl/cxl-device-utils.c | 17 +++++++++++------ + include/hw/cxl/cxl_device.h | 9 +++++++-- + 2 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c +index 61a3c4d..40b619f 100644 +--- a/hw/cxl/cxl-device-utils.c ++++ b/hw/cxl/cxl-device-utils.c +@@ -229,12 +229,9 @@ static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value, + + static uint64_t mdev_reg_read(void *opaque, hwaddr offset, unsigned size) + { +- uint64_t retval = 0; +- +- retval = FIELD_DP64(retval, CXL_MEM_DEV_STS, MEDIA_STATUS, 1); +- retval = FIELD_DP64(retval, CXL_MEM_DEV_STS, MBOX_READY, 1); ++ CXLDeviceState *cxl_dstate = opaque; + +- return retval; ++ return cxl_dstate->memdev_status; + } + + static void ro_reg_write(void *opaque, hwaddr offset, uint64_t value, +@@ -371,7 +368,15 @@ static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate) + cxl_dstate->mbox_msi_n = msi_n; + } + +-static void memdev_reg_init_common(CXLDeviceState *cxl_dstate) { } ++static void memdev_reg_init_common(CXLDeviceState *cxl_dstate) ++{ ++ uint64_t memdev_status_reg; ++ ++ memdev_status_reg = FIELD_DP64(0, CXL_MEM_DEV_STS, MEDIA_STATUS, 1); ++ memdev_status_reg = FIELD_DP64(memdev_status_reg, CXL_MEM_DEV_STS, ++ MBOX_READY, 1); ++ cxl_dstate->memdev_status = memdev_status_reg; ++} + + void cxl_device_register_init_t3(CXLType3Dev *ct3d) + { +diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h +index befb5f8..31d2afc 100644 +--- a/include/hw/cxl/cxl_device.h ++++ b/include/hw/cxl/cxl_device.h +@@ -202,6 +202,9 @@ typedef struct cxl_device_state { + }; + }; + ++ /* Stash the memory device status value */ ++ uint64_t memdev_status; ++ + struct { + bool set; + uint64_t last_set; +@@ -353,8 +356,10 @@ static inline void __toggle_media(CXLDeviceState *cxl_dstate, int val) + { + uint64_t dev_status_reg; + +- dev_status_reg = FIELD_DP64(0, CXL_MEM_DEV_STS, MEDIA_STATUS, val); +- cxl_dstate->mbox_reg_state64[R_CXL_MEM_DEV_STS] = dev_status_reg; ++ dev_status_reg = cxl_dstate->memdev_status; ++ dev_status_reg = FIELD_DP64(dev_status_reg, CXL_MEM_DEV_STS, MEDIA_STATUS, ++ val); ++ cxl_dstate->memdev_status = dev_status_reg; + } + #define cxl_dev_disable_media(cxlds) \ + do { __toggle_media((cxlds), 0x3); } while (0) +-- +1.8.3.1 + diff --git a/0098-hw-cxl-Pass-CXLComponentState-to-cache_mem_ops.patch b/0098-hw-cxl-Pass-CXLComponentState-to-cache_mem_ops.patch new file mode 100644 index 0000000000000000000000000000000000000000..0eeb8e8d2c0ed4b656606c943d2c1606deb0b5e7 --- /dev/null +++ b/0098-hw-cxl-Pass-CXLComponentState-to-cache_mem_ops.patch @@ -0,0 +1,40 @@ +From bbe51d6ea3a9adcca3b46ce8f19b9b4ead488e28 Mon Sep 17 00:00:00 2001 +From: Li Zhijian +Date: Fri, 26 Jan 2024 12:01:27 +0000 +Subject: [PATCH 105/293] hw/cxl: Pass CXLComponentState to cache_mem_ops + +cache_mem_ops.{read,write}() interprets opaque as +CXLComponentState(cxl_cstate) instead of ComponentRegisters(cregs). + +Fortunately, cregs is the first member of cxl_cstate, so their values are +the same. + +Fixes: 9e58f52d3f8 ("hw/cxl/component: Introduce CXL components (8.1.x, 8.2.5)") +Reviewed-by: Fan Ni +Signed-off-by: Li Zhijian +Signed-off-by: Jonathan Cameron +Message-Id: <20240126120132.24248-8-Jonathan.Cameron@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 729d45a6af06753d3e330f589c248fe9687c5cd5) +Signed-off-by: Michael Tokarev +--- + hw/cxl/cxl-component-utils.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c +index 29d4774..9dfde6c 100644 +--- a/hw/cxl/cxl-component-utils.c ++++ b/hw/cxl/cxl-component-utils.c +@@ -199,7 +199,7 @@ void cxl_component_register_block_init(Object *obj, + /* io registers controls link which we don't care about in QEMU */ + memory_region_init_io(&cregs->io, obj, NULL, cregs, ".io", + CXL2_COMPONENT_IO_REGION_SIZE); +- memory_region_init_io(&cregs->cache_mem, obj, &cache_mem_ops, cregs, ++ memory_region_init_io(&cregs->cache_mem, obj, &cache_mem_ops, cxl_cstate, + ".cache_mem", CXL2_COMPONENT_CM_REGION_SIZE); + + memory_region_add_subregion(&cregs->component_registers, 0, &cregs->io); +-- +1.8.3.1 + diff --git a/0099-virtio-gpu-Correct-virgl_renderer_resource_get_info-.patch b/0099-virtio-gpu-Correct-virgl_renderer_resource_get_info-.patch new file mode 100644 index 0000000000000000000000000000000000000000..d82a2942353361e568d29226259b166a272fe27f --- /dev/null +++ b/0099-virtio-gpu-Correct-virgl_renderer_resource_get_info-.patch @@ -0,0 +1,72 @@ +From 1c38c8a24a9d053d42e3892fddf18421cf3a67d3 Mon Sep 17 00:00:00 2001 +From: Dmitry Osipenko +Date: Mon, 29 Jan 2024 10:39:21 +0300 +Subject: [PATCH 106/293] virtio-gpu: Correct + virgl_renderer_resource_get_info() error check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +virgl_renderer_resource_get_info() returns errno and not -1 on error. +Correct the return-value check. + +Reviewed-by: Marc-André Lureau +Signed-off-by: Dmitry Osipenko +Message-Id: <20240129073921.446869-1-dmitry.osipenko@collabora.com> +Cc: qemu-stable@nongnu.org +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 574b64aa6754ba491f51024c5a823a674d48a658) +Signed-off-by: Michael Tokarev +--- + contrib/vhost-user-gpu/virgl.c | 6 +++--- + hw/display/virtio-gpu-virgl.c | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/contrib/vhost-user-gpu/virgl.c b/contrib/vhost-user-gpu/virgl.c +index d1ccdf7..51da0e3 100644 +--- a/contrib/vhost-user-gpu/virgl.c ++++ b/contrib/vhost-user-gpu/virgl.c +@@ -327,7 +327,7 @@ virgl_get_resource_info_modifiers(uint32_t resource_id, + #ifdef VIRGL_RENDERER_RESOURCE_INFO_EXT_VERSION + struct virgl_renderer_resource_info_ext info_ext; + ret = virgl_renderer_resource_get_info_ext(resource_id, &info_ext); +- if (ret < 0) { ++ if (ret) { + return ret; + } + +@@ -335,7 +335,7 @@ virgl_get_resource_info_modifiers(uint32_t resource_id, + *modifiers = info_ext.modifiers; + #else + ret = virgl_renderer_resource_get_info(resource_id, info); +- if (ret < 0) { ++ if (ret) { + return ret; + } + +@@ -372,7 +372,7 @@ virgl_cmd_set_scanout(VuGpu *g, + uint64_t modifiers = 0; + ret = virgl_get_resource_info_modifiers(ss.resource_id, &info, + &modifiers); +- if (ret == -1) { ++ if (ret) { + g_critical("%s: illegal resource specified %d\n", + __func__, ss.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c +index 8bb7a2c..9f34d0e 100644 +--- a/hw/display/virtio-gpu-virgl.c ++++ b/hw/display/virtio-gpu-virgl.c +@@ -181,7 +181,7 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g, + memset(&info, 0, sizeof(info)); + ret = virgl_renderer_resource_get_info(ss.resource_id, &info); + #endif +- if (ret == -1) { ++ if (ret) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: illegal resource specified %d\n", + __func__, ss.resource_id); +-- +1.8.3.1 + diff --git a/0100-virtio_iommu-Clear-IOMMUPciBus-pointer-cache-when-sy.patch b/0100-virtio_iommu-Clear-IOMMUPciBus-pointer-cache-when-sy.patch new file mode 100644 index 0000000000000000000000000000000000000000..e10e8c553888b69f21e51b98f09af80e5abeccfa --- /dev/null +++ b/0100-virtio_iommu-Clear-IOMMUPciBus-pointer-cache-when-sy.patch @@ -0,0 +1,55 @@ +From 721c3ceaeffed4d9adf9bb0062431483792c57b7 Mon Sep 17 00:00:00 2001 +From: Zhenzhong Duan +Date: Thu, 25 Jan 2024 15:37:05 +0800 +Subject: [PATCH 107/293] virtio_iommu: Clear IOMMUPciBus pointer cache when + system reset + +s->iommu_pcibus_by_bus_num is a IOMMUPciBus pointer cache indexed +by bus number, bus number may not always be a fixed value, +i.e., guest reboot to different kernel which set bus number with +different algorithm. + +This could lead to endpoint binding to wrong iommu MR in +virtio_iommu_get_endpoint(), then vfio device setup wrong +mapping from other device. + +Remove the memset in virtio_iommu_device_realize() to avoid +redundancy with memset in system reset. + +Signed-off-by: Zhenzhong Duan +Message-Id: <20240125073706.339369-2-zhenzhong.duan@intel.com> +Reviewed-by: Eric Auger +Tested-by: Eric Auger +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 9a457383ce9d309d4679b079fafb51f0a2d949aa) +Signed-off-by: Michael Tokarev +--- + hw/virtio/virtio-iommu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c +index 9d463ef..90a7ca2 100644 +--- a/hw/virtio/virtio-iommu.c ++++ b/hw/virtio/virtio-iommu.c +@@ -1264,6 +1264,8 @@ static void virtio_iommu_system_reset(void *opaque) + + trace_virtio_iommu_system_reset(); + ++ memset(s->iommu_pcibus_by_bus_num, 0, sizeof(s->iommu_pcibus_by_bus_num)); ++ + /* + * config.bypass is sticky across device reset, but should be restored on + * system reset +@@ -1302,8 +1304,6 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) + + virtio_init(vdev, VIRTIO_ID_IOMMU, sizeof(struct virtio_iommu_config)); + +- memset(s->iommu_pcibus_by_bus_num, 0, sizeof(s->iommu_pcibus_by_bus_num)); +- + s->req_vq = virtio_add_queue(vdev, VIOMMU_DEFAULT_QUEUE_SIZE, + virtio_iommu_handle_command); + s->event_vq = virtio_add_queue(vdev, VIOMMU_DEFAULT_QUEUE_SIZE, NULL); +-- +1.8.3.1 + diff --git a/0101-smmu-Clear-SMMUPciBus-pointer-cache-when-system-rese.patch b/0101-smmu-Clear-SMMUPciBus-pointer-cache-when-system-rese.patch new file mode 100644 index 0000000000000000000000000000000000000000..004f4c378c0868b9423901dd04058455ff6f9e9d --- /dev/null +++ b/0101-smmu-Clear-SMMUPciBus-pointer-cache-when-system-rese.patch @@ -0,0 +1,42 @@ +From d4157195bd3b8753dc422085623e415d0bab3bb9 Mon Sep 17 00:00:00 2001 +From: Zhenzhong Duan +Date: Thu, 25 Jan 2024 15:37:06 +0800 +Subject: [PATCH 108/293] smmu: Clear SMMUPciBus pointer cache when system + reset + +s->smmu_pcibus_by_bus_num is a SMMUPciBus pointer cache indexed +by bus number, bus number may not always be a fixed value, +i.e., guest reboot to different kernel which set bus number with +different algorithm. + +This could lead to smmu_iommu_mr() providing the wrong iommu MR. + +Suggested-by: Eric Auger +Signed-off-by: Zhenzhong Duan +Message-Id: <20240125073706.339369-3-zhenzhong.duan@intel.com> +Reviewed-by: Eric Auger +Tested-by: Eric Auger +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 8a6b3f4dc95a064e88adaca86374108da0ecb38d) +Signed-off-by: Michael Tokarev +--- + hw/arm/smmu-common.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c +index 9a8ac45..f58261b 100644 +--- a/hw/arm/smmu-common.c ++++ b/hw/arm/smmu-common.c +@@ -675,6 +675,8 @@ static void smmu_base_reset_hold(Object *obj) + { + SMMUState *s = ARM_SMMU(obj); + ++ memset(s->smmu_pcibus_by_bus_num, 0, sizeof(s->smmu_pcibus_by_bus_num)); ++ + g_hash_table_remove_all(s->configs); + g_hash_table_remove_all(s->iotlb); + } +-- +1.8.3.1 + diff --git a/0102-tests-acpi-Allow-update-of-DSDT.cxl.patch b/0102-tests-acpi-Allow-update-of-DSDT.cxl.patch new file mode 100644 index 0000000000000000000000000000000000000000..538fa88482ec25904ed60ef93c1bb6578e7e986b --- /dev/null +++ b/0102-tests-acpi-Allow-update-of-DSDT.cxl.patch @@ -0,0 +1,30 @@ +From 47df9ca585cbc1c14f197af1a05a236a3fad9920 Mon Sep 17 00:00:00 2001 +From: Jonathan Cameron +Date: Fri, 26 Jan 2024 12:01:30 +0000 +Subject: [PATCH 109/293] tests/acpi: Allow update of DSDT.cxl + +The _STA value returned currently indicates the ACPI0017 device +is not enabled. Whilst this isn't a real device, setting _STA +like this may prevent an OS from enumerating it correctly and +hence from parsing the CEDT table. + +Signed-off-by: Jonathan Cameron +Message-Id: <20240126120132.24248-11-Jonathan.Cameron@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 14ec4ff3e4293635240ba5a7afe7a0f3ba447d31) +Signed-off-by: Michael Tokarev +--- + tests/qtest/bios-tables-test-allowed-diff.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h +index dfb8523..9ce0f59 100644 +--- a/tests/qtest/bios-tables-test-allowed-diff.h ++++ b/tests/qtest/bios-tables-test-allowed-diff.h +@@ -1 +1,2 @@ + /* List of comma-separated changed AML files to ignore */ ++"tests/data/acpi/q35/DSDT.cxl", +-- +1.8.3.1 + diff --git a/0103-hw-i386-Fix-_STA-return-value-for-ACPI0017.patch b/0103-hw-i386-Fix-_STA-return-value-for-ACPI0017.patch new file mode 100644 index 0000000000000000000000000000000000000000..77866597c48241d53977d8e98ea47961e4930e20 --- /dev/null +++ b/0103-hw-i386-Fix-_STA-return-value-for-ACPI0017.patch @@ -0,0 +1,46 @@ +From 02d9979ba8f0bc504be36860969c6c6921816841 Mon Sep 17 00:00:00 2001 +From: Jonathan Cameron +Date: Fri, 26 Jan 2024 12:01:31 +0000 +Subject: [PATCH 110/293] hw/i386: Fix _STA return value for ACPI0017 + +Found whilst testing a series for the linux kernel that actually +bothers to check if enabled is set. 0xB is the option used +for vast majority of DSDT entries in QEMU. +It is a little odd for a device that doesn't really exist and +is simply a hook to tell the OS there is a CEDT table but 0xB +seems a reasonable choice and avoids need to special case +this device in the OS. + +Means: +* Device present. +* Device enabled and decoding it's resources. +* Not shown in UI +* Functioning properly +* No battery (on this device!) + +Signed-off-by: Jonathan Cameron +Message-Id: <20240126120132.24248-12-Jonathan.Cameron@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit d9ae5802f656f6fb53b788747ba557a826b6e740) +Signed-off-by: Michael Tokarev +--- + hw/i386/acpi-build.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 80db183..1e17834 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -1415,7 +1415,7 @@ static void build_acpi0017(Aml *table) + aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0017"))); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); +- aml_append(method, aml_return(aml_int(0x01))); ++ aml_append(method, aml_return(aml_int(0x0B))); + aml_append(dev, method); + build_cxl_dsm_method(dev); + +-- +1.8.3.1 + diff --git a/0104-linux-user-aarch64-Choose-SYNC-as-the-preferred-MTE-.patch b/0104-linux-user-aarch64-Choose-SYNC-as-the-preferred-MTE-.patch new file mode 100644 index 0000000000000000000000000000000000000000..351cdbb5903f9cf67c1b40d2d8311a96b481beb0 --- /dev/null +++ b/0104-linux-user-aarch64-Choose-SYNC-as-the-preferred-MTE-.patch @@ -0,0 +1,68 @@ +From 7950913ece574bc12089cca421e1a51d891b963e Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Thu, 15 Feb 2024 11:30:44 +0000 +Subject: [PATCH 112/293] linux-user/aarch64: Choose SYNC as the preferred MTE + mode + +The API does not generate an error for setting ASYNC | SYNC; that merely +constrains the selection vs the per-cpu default. For qemu linux-user, +choose SYNC as the default. + +Cc: qemu-stable@nongnu.org +Reported-by: Gustavo Romero +Signed-off-by: Richard Henderson +Tested-by: Gustavo Romero +Message-id: 20240207025210.8837-2-richard.henderson@linaro.org +Signed-off-by: Peter Maydell +(cherry picked from commit 681dfc0d552963d4d598350d26097a692900b408) +Signed-off-by: Michael Tokarev +--- + linux-user/aarch64/target_prctl.h | 29 +++++++++++++++++------------ + 1 file changed, 17 insertions(+), 12 deletions(-) + +diff --git a/linux-user/aarch64/target_prctl.h b/linux-user/aarch64/target_prctl.h +index 5067e7d..aa8e203 100644 +--- a/linux-user/aarch64/target_prctl.h ++++ b/linux-user/aarch64/target_prctl.h +@@ -173,21 +173,26 @@ static abi_long do_prctl_set_tagged_addr_ctrl(CPUArchState *env, abi_long arg2) + env->tagged_addr_enable = arg2 & PR_TAGGED_ADDR_ENABLE; + + if (cpu_isar_feature(aa64_mte, cpu)) { +- switch (arg2 & PR_MTE_TCF_MASK) { +- case PR_MTE_TCF_NONE: +- case PR_MTE_TCF_SYNC: +- case PR_MTE_TCF_ASYNC: +- break; +- default: +- return -EINVAL; +- } +- + /* + * Write PR_MTE_TCF to SCTLR_EL1[TCF0]. +- * Note that the syscall values are consistent with hw. ++ * ++ * The kernel has a per-cpu configuration for the sysadmin, ++ * /sys/devices/system/cpu/cpu/mte_tcf_preferred, ++ * which qemu does not implement. ++ * ++ * Because there is no performance difference between the modes, and ++ * because SYNC is most useful for debugging MTE errors, choose SYNC ++ * as the preferred mode. With this preference, and the way the API ++ * uses only two bits, there is no way for the program to select ++ * ASYMM mode. + */ +- env->cp15.sctlr_el[1] = +- deposit64(env->cp15.sctlr_el[1], 38, 2, arg2 >> PR_MTE_TCF_SHIFT); ++ unsigned tcf = 0; ++ if (arg2 & PR_MTE_TCF_SYNC) { ++ tcf = 1; ++ } else if (arg2 & PR_MTE_TCF_ASYNC) { ++ tcf = 2; ++ } ++ env->cp15.sctlr_el[1] = deposit64(env->cp15.sctlr_el[1], 38, 2, tcf); + + /* + * Write PR_MTE_TAG to GCR_EL1[Exclude]. +-- +1.8.3.1 + diff --git a/0105-target-arm-Fix-nregs-computation-in-do_-ld-st-_zpa.patch b/0105-target-arm-Fix-nregs-computation-in-do_-ld-st-_zpa.patch new file mode 100644 index 0000000000000000000000000000000000000000..324d8ade746449152903ef966ee2eeda256c3cb2 --- /dev/null +++ b/0105-target-arm-Fix-nregs-computation-in-do_-ld-st-_zpa.patch @@ -0,0 +1,82 @@ +From 5e6e09baa516fd7c768cc1050a6ed638574e8047 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Thu, 15 Feb 2024 11:30:44 +0000 +Subject: [PATCH 113/293] target/arm: Fix nregs computation in do_{ld,st}_zpa + +The field is encoded as [0-3], which is convenient for +indexing our array of function pointers, but the true +value is [1-4]. Adjust before calling do_mem_zpa. + +Add an assert, and move the comment re passing ZT to +the helper back next to the relevant code. + +Cc: qemu-stable@nongnu.org +Fixes: 206adacfb8d ("target/arm: Add mte helpers for sve scalar + int loads") +Signed-off-by: Richard Henderson +Tested-by: Gustavo Romero +Message-id: 20240207025210.8837-3-richard.henderson@linaro.org +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +(cherry picked from commit 64c6e7444dff64b42d11b836b9aec9acfbe8ecc2) +Signed-off-by: Michael Tokarev +--- + target/arm/tcg/translate-sve.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c +index 296e7d1..7108938 100644 +--- a/target/arm/tcg/translate-sve.c ++++ b/target/arm/tcg/translate-sve.c +@@ -4445,11 +4445,7 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, + TCGv_ptr t_pg; + int desc = 0; + +- /* +- * For e.g. LD4, there are not enough arguments to pass all 4 +- * registers as pointers, so encode the regno into the data field. +- * For consistency, do this even for LD1. +- */ ++ assert(mte_n >= 1 && mte_n <= 4); + if (s->mte_active[0]) { + int msz = dtype_msz(dtype); + +@@ -4463,6 +4459,11 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, + addr = clean_data_tbi(s, addr); + } + ++ /* ++ * For e.g. LD4, there are not enough arguments to pass all 4 ++ * registers as pointers, so encode the regno into the data field. ++ * For consistency, do this even for LD1. ++ */ + desc = simd_desc(vsz, vsz, zt | desc); + t_pg = tcg_temp_new_ptr(); + +@@ -4600,7 +4601,7 @@ static void do_ld_zpa(DisasContext *s, int zt, int pg, + * accessible via the instruction encoding. + */ + assert(fn != NULL); +- do_mem_zpa(s, zt, pg, addr, dtype, nreg, false, fn); ++ do_mem_zpa(s, zt, pg, addr, dtype, nreg + 1, false, fn); + } + + static bool trans_LD_zprr(DisasContext *s, arg_rprr_load *a) +@@ -5168,14 +5169,13 @@ static void do_st_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, + if (nreg == 0) { + /* ST1 */ + fn = fn_single[s->mte_active[0]][be][msz][esz]; +- nreg = 1; + } else { + /* ST2, ST3, ST4 -- msz == esz, enforced by encoding */ + assert(msz == esz); + fn = fn_multiple[s->mte_active[0]][be][nreg - 1][msz]; + } + assert(fn != NULL); +- do_mem_zpa(s, zt, pg, addr, msz_dtype(s, msz), nreg, true, fn); ++ do_mem_zpa(s, zt, pg, addr, msz_dtype(s, msz), nreg + 1, true, fn); + } + + static bool trans_ST_zprr(DisasContext *s, arg_rprr_store *a) +-- +1.8.3.1 + diff --git a/0106-target-arm-Adjust-and-validate-mtedesc-sizem1.patch b/0106-target-arm-Adjust-and-validate-mtedesc-sizem1.patch new file mode 100644 index 0000000000000000000000000000000000000000..0b03bcbca9fa93c82f50fdcf40e4cc24c7d070ea --- /dev/null +++ b/0106-target-arm-Adjust-and-validate-mtedesc-sizem1.patch @@ -0,0 +1,65 @@ +From 8da74af97029dc96205ed4ddd53230d6d99c15c3 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Thu, 15 Feb 2024 11:30:44 +0000 +Subject: [PATCH 114/293] target/arm: Adjust and validate mtedesc sizem1 + +When we added SVE_MTEDESC_SHIFT, we effectively limited the +maximum size of MTEDESC. Adjust SIZEM1 to consume the remaining +bits (32 - 10 - 5 - 12 == 5). Assert that the data to be stored +fits within the field (expecting 8 * 4 - 1 == 31, exact fit). + +Cc: qemu-stable@nongnu.org +Reviewed-by: Peter Maydell +Signed-off-by: Richard Henderson +Tested-by: Gustavo Romero +Message-id: 20240207025210.8837-4-richard.henderson@linaro.org +Signed-off-by: Peter Maydell +(cherry picked from commit b12a7671b6099a26ce5d5ab09701f151e21c112c) +Signed-off-by: Michael Tokarev +--- + target/arm/internals.h | 2 +- + target/arm/tcg/translate-sve.c | 7 ++++--- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/target/arm/internals.h b/target/arm/internals.h +index 143d57c..8342f46 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -1273,7 +1273,7 @@ FIELD(MTEDESC, TBI, 4, 2) + FIELD(MTEDESC, TCMA, 6, 2) + FIELD(MTEDESC, WRITE, 8, 1) + FIELD(MTEDESC, ALIGN, 9, 3) +-FIELD(MTEDESC, SIZEM1, 12, SIMD_DATA_BITS - 12) /* size - 1 */ ++FIELD(MTEDESC, SIZEM1, 12, SIMD_DATA_BITS - SVE_MTEDESC_SHIFT - 12) /* size - 1 */ + + bool mte_probe(CPUARMState *env, uint32_t desc, uint64_t ptr); + uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra); +diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c +index 7108938..a88e523 100644 +--- a/target/arm/tcg/translate-sve.c ++++ b/target/arm/tcg/translate-sve.c +@@ -4443,17 +4443,18 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, + { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr t_pg; ++ uint32_t sizem1; + int desc = 0; + + assert(mte_n >= 1 && mte_n <= 4); ++ sizem1 = (mte_n << dtype_msz(dtype)) - 1; ++ assert(sizem1 <= R_MTEDESC_SIZEM1_MASK >> R_MTEDESC_SIZEM1_SHIFT); + if (s->mte_active[0]) { +- int msz = dtype_msz(dtype); +- + desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); + desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); + desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); + desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); +- desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (mte_n << msz) - 1); ++ desc = FIELD_DP32(desc, MTEDESC, SIZEM1, sizem1); + desc <<= SVE_MTEDESC_SHIFT; + } else { + addr = clean_data_tbi(s, addr); +-- +1.8.3.1 + diff --git a/0107-target-arm-Split-out-make_svemte_desc.patch b/0107-target-arm-Split-out-make_svemte_desc.patch new file mode 100644 index 0000000000000000000000000000000000000000..3d85426464ac4af19526e8148e02651105a80d83 --- /dev/null +++ b/0107-target-arm-Split-out-make_svemte_desc.patch @@ -0,0 +1,162 @@ +From da804717a549118ef4fc1351540737444ffbb5b0 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Thu, 15 Feb 2024 11:30:45 +0000 +Subject: [PATCH 115/293] target/arm: Split out make_svemte_desc + +Share code that creates mtedesc and embeds within simd_desc. + +Cc: qemu-stable@nongnu.org +Reviewed-by: Peter Maydell +Signed-off-by: Richard Henderson +Tested-by: Gustavo Romero +Message-id: 20240207025210.8837-5-richard.henderson@linaro.org +Signed-off-by: Peter Maydell +(cherry picked from commit 96fcc9982b4aad7aced7fbff046048bbccc6cb0c) +Signed-off-by: Michael Tokarev +--- + target/arm/tcg/translate-a64.h | 2 ++ + target/arm/tcg/translate-sme.c | 15 ++++---------- + target/arm/tcg/translate-sve.c | 47 ++++++++++++++++++++++-------------------- + 3 files changed, 31 insertions(+), 33 deletions(-) + +diff --git a/target/arm/tcg/translate-a64.h b/target/arm/tcg/translate-a64.h +index 96ba39b..7b811b8 100644 +--- a/target/arm/tcg/translate-a64.h ++++ b/target/arm/tcg/translate-a64.h +@@ -28,6 +28,8 @@ bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn, + bool sve_access_check(DisasContext *s); + bool sme_enabled_check(DisasContext *s); + bool sme_enabled_check_with_svcr(DisasContext *s, unsigned); ++uint32_t make_svemte_desc(DisasContext *s, unsigned vsz, uint32_t nregs, ++ uint32_t msz, bool is_write, uint32_t data); + + /* This function corresponds to CheckStreamingSVEEnabled. */ + static inline bool sme_sm_enabled_check(DisasContext *s) +diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c +index 8f0dfc8..46c7fce 100644 +--- a/target/arm/tcg/translate-sme.c ++++ b/target/arm/tcg/translate-sme.c +@@ -206,7 +206,7 @@ static bool trans_LDST1(DisasContext *s, arg_LDST1 *a) + + TCGv_ptr t_za, t_pg; + TCGv_i64 addr; +- int svl, desc = 0; ++ uint32_t desc; + bool be = s->be_data == MO_BE; + bool mte = s->mte_active[0]; + +@@ -224,18 +224,11 @@ static bool trans_LDST1(DisasContext *s, arg_LDST1 *a) + tcg_gen_shli_i64(addr, cpu_reg(s, a->rm), a->esz); + tcg_gen_add_i64(addr, addr, cpu_reg_sp(s, a->rn)); + +- if (mte) { +- desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); +- desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); +- desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); +- desc = FIELD_DP32(desc, MTEDESC, WRITE, a->st); +- desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (1 << a->esz) - 1); +- desc <<= SVE_MTEDESC_SHIFT; +- } else { ++ if (!mte) { + addr = clean_data_tbi(s, addr); + } +- svl = streaming_vec_reg_size(s); +- desc = simd_desc(svl, svl, desc); ++ ++ desc = make_svemte_desc(s, streaming_vec_reg_size(s), 1, a->esz, a->st, 0); + + fns[a->esz][be][a->v][mte][a->st](tcg_env, t_za, t_pg, addr, + tcg_constant_i32(desc)); +diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c +index a88e523..508f7b6 100644 +--- a/target/arm/tcg/translate-sve.c ++++ b/target/arm/tcg/translate-sve.c +@@ -4437,18 +4437,18 @@ static const uint8_t dtype_esz[16] = { + 3, 2, 1, 3 + }; + +-static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, +- int dtype, uint32_t mte_n, bool is_write, +- gen_helper_gvec_mem *fn) ++uint32_t make_svemte_desc(DisasContext *s, unsigned vsz, uint32_t nregs, ++ uint32_t msz, bool is_write, uint32_t data) + { +- unsigned vsz = vec_full_reg_size(s); +- TCGv_ptr t_pg; + uint32_t sizem1; +- int desc = 0; ++ uint32_t desc = 0; + +- assert(mte_n >= 1 && mte_n <= 4); +- sizem1 = (mte_n << dtype_msz(dtype)) - 1; ++ /* Assert all of the data fits, with or without MTE enabled. */ ++ assert(nregs >= 1 && nregs <= 4); ++ sizem1 = (nregs << msz) - 1; + assert(sizem1 <= R_MTEDESC_SIZEM1_MASK >> R_MTEDESC_SIZEM1_SHIFT); ++ assert(data < 1u << SVE_MTEDESC_SHIFT); ++ + if (s->mte_active[0]) { + desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); + desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); +@@ -4456,7 +4456,18 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, + desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); + desc = FIELD_DP32(desc, MTEDESC, SIZEM1, sizem1); + desc <<= SVE_MTEDESC_SHIFT; +- } else { ++ } ++ return simd_desc(vsz, vsz, desc | data); ++} ++ ++static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, ++ int dtype, uint32_t nregs, bool is_write, ++ gen_helper_gvec_mem *fn) ++{ ++ TCGv_ptr t_pg; ++ uint32_t desc; ++ ++ if (!s->mte_active[0]) { + addr = clean_data_tbi(s, addr); + } + +@@ -4465,7 +4476,8 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, + * registers as pointers, so encode the regno into the data field. + * For consistency, do this even for LD1. + */ +- desc = simd_desc(vsz, vsz, zt | desc); ++ desc = make_svemte_desc(s, vec_full_reg_size(s), nregs, ++ dtype_msz(dtype), is_write, zt); + t_pg = tcg_temp_new_ptr(); + + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, pg)); +@@ -5224,25 +5236,16 @@ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm, + int scale, TCGv_i64 scalar, int msz, bool is_write, + gen_helper_gvec_mem_scatter *fn) + { +- unsigned vsz = vec_full_reg_size(s); + TCGv_ptr t_zm = tcg_temp_new_ptr(); + TCGv_ptr t_pg = tcg_temp_new_ptr(); + TCGv_ptr t_zt = tcg_temp_new_ptr(); +- int desc = 0; +- +- if (s->mte_active[0]) { +- desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); +- desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); +- desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); +- desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); +- desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (1 << msz) - 1); +- desc <<= SVE_MTEDESC_SHIFT; +- } +- desc = simd_desc(vsz, vsz, desc | scale); ++ uint32_t desc; + + tcg_gen_addi_ptr(t_pg, tcg_env, pred_full_reg_offset(s, pg)); + tcg_gen_addi_ptr(t_zm, tcg_env, vec_full_reg_offset(s, zm)); + tcg_gen_addi_ptr(t_zt, tcg_env, vec_full_reg_offset(s, zt)); ++ ++ desc = make_svemte_desc(s, vec_full_reg_size(s), 1, msz, is_write, scale); + fn(tcg_env, t_zt, t_pg, t_zm, scalar, tcg_constant_i32(desc)); + } + +-- +1.8.3.1 + diff --git a/0108-target-arm-Handle-mte-in-do_ldrq-do_ldro.patch b/0108-target-arm-Handle-mte-in-do_ldrq-do_ldro.patch new file mode 100644 index 0000000000000000000000000000000000000000..1d98a1441ab2259aad72479a93e131130e1d6901 --- /dev/null +++ b/0108-target-arm-Handle-mte-in-do_ldrq-do_ldro.patch @@ -0,0 +1,79 @@ +From 2d1a29e3b23d833c22ef01df9b6ceb7200275fd3 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Thu, 15 Feb 2024 11:30:45 +0000 +Subject: [PATCH 116/293] target/arm: Handle mte in do_ldrq, do_ldro + +These functions "use the standard load helpers", but +fail to clean_data_tbi or populate mtedesc. + +Cc: qemu-stable@nongnu.org +Reviewed-by: Peter Maydell +Signed-off-by: Richard Henderson +Tested-by: Gustavo Romero +Message-id: 20240207025210.8837-6-richard.henderson@linaro.org +Signed-off-by: Peter Maydell +(cherry picked from commit 623507ccfcfebb0f10229ae5de3f85a27fb615a7) +Signed-off-by: Michael Tokarev +--- + target/arm/tcg/translate-sve.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c +index 508f7b6..ada05aa 100644 +--- a/target/arm/tcg/translate-sve.c ++++ b/target/arm/tcg/translate-sve.c +@@ -4861,8 +4861,13 @@ static void do_ldrq(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr t_pg; + int poff; ++ uint32_t desc; + + /* Load the first quadword using the normal predicated load helpers. */ ++ if (!s->mte_active[0]) { ++ addr = clean_data_tbi(s, addr); ++ } ++ + poff = pred_full_reg_offset(s, pg); + if (vsz > 16) { + /* +@@ -4886,7 +4891,8 @@ static void do_ldrq(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) + + gen_helper_gvec_mem *fn + = ldr_fns[s->mte_active[0]][s->be_data == MO_BE][dtype][0]; +- fn(tcg_env, t_pg, addr, tcg_constant_i32(simd_desc(16, 16, zt))); ++ desc = make_svemte_desc(s, 16, 1, dtype_msz(dtype), false, zt); ++ fn(tcg_env, t_pg, addr, tcg_constant_i32(desc)); + + /* Replicate that first quadword. */ + if (vsz > 16) { +@@ -4929,6 +4935,7 @@ static void do_ldro(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) + unsigned vsz_r32; + TCGv_ptr t_pg; + int poff, doff; ++ uint32_t desc; + + if (vsz < 32) { + /* +@@ -4941,6 +4948,9 @@ static void do_ldro(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) + } + + /* Load the first octaword using the normal predicated load helpers. */ ++ if (!s->mte_active[0]) { ++ addr = clean_data_tbi(s, addr); ++ } + + poff = pred_full_reg_offset(s, pg); + if (vsz > 32) { +@@ -4965,7 +4975,8 @@ static void do_ldro(DisasContext *s, int zt, int pg, TCGv_i64 addr, int dtype) + + gen_helper_gvec_mem *fn + = ldr_fns[s->mte_active[0]][s->be_data == MO_BE][dtype][0]; +- fn(tcg_env, t_pg, addr, tcg_constant_i32(simd_desc(32, 32, zt))); ++ desc = make_svemte_desc(s, 32, 1, dtype_msz(dtype), false, zt); ++ fn(tcg_env, t_pg, addr, tcg_constant_i32(desc)); + + /* + * Replicate that first octaword. +-- +1.8.3.1 + diff --git a/0109-target-arm-Fix-SVE-SME-gross-MTE-suppression-checks.patch b/0109-target-arm-Fix-SVE-SME-gross-MTE-suppression-checks.patch new file mode 100644 index 0000000000000000000000000000000000000000..884447c125f08b1f2b414a6ff542e57639895ebb --- /dev/null +++ b/0109-target-arm-Fix-SVE-SME-gross-MTE-suppression-checks.patch @@ -0,0 +1,86 @@ +From 429c11c7266b14f3ce0a052cd582095fdf085d56 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Thu, 15 Feb 2024 11:30:45 +0000 +Subject: [PATCH 117/293] target/arm: Fix SVE/SME gross MTE suppression checks + +The TBI and TCMA bits are located within mtedesc, not desc. + +Cc: qemu-stable@nongnu.org +Reviewed-by: Peter Maydell +Signed-off-by: Richard Henderson +Tested-by: Gustavo Romero +Message-id: 20240207025210.8837-7-richard.henderson@linaro.org +Signed-off-by: Peter Maydell +(cherry picked from commit 855f94eca80c85a99f459e36684ea2f98f6a3243) +Signed-off-by: Michael Tokarev +--- + target/arm/tcg/sme_helper.c | 8 ++++---- + target/arm/tcg/sve_helper.c | 12 ++++++------ + 2 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c +index 1ee2690..904bfda 100644 +--- a/target/arm/tcg/sme_helper.c ++++ b/target/arm/tcg/sme_helper.c +@@ -573,8 +573,8 @@ void sme_ld1_mte(CPUARMState *env, void *za, uint64_t *vg, + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* Perform gross MTE suppression early. */ +- if (!tbi_check(desc, bit55) || +- tcma_check(desc, bit55, allocation_tag_from_addr(addr))) { ++ if (!tbi_check(mtedesc, bit55) || ++ tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) { + mtedesc = 0; + } + +@@ -750,8 +750,8 @@ void sme_st1_mte(CPUARMState *env, void *za, uint64_t *vg, target_ulong addr, + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* Perform gross MTE suppression early. */ +- if (!tbi_check(desc, bit55) || +- tcma_check(desc, bit55, allocation_tag_from_addr(addr))) { ++ if (!tbi_check(mtedesc, bit55) || ++ tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) { + mtedesc = 0; + } + +diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c +index f006d15..5699dfe 100644 +--- a/target/arm/tcg/sve_helper.c ++++ b/target/arm/tcg/sve_helper.c +@@ -5800,8 +5800,8 @@ void sve_ldN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr, + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* Perform gross MTE suppression early. */ +- if (!tbi_check(desc, bit55) || +- tcma_check(desc, bit55, allocation_tag_from_addr(addr))) { ++ if (!tbi_check(mtedesc, bit55) || ++ tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) { + mtedesc = 0; + } + +@@ -6156,8 +6156,8 @@ void sve_ldnfff1_r_mte(CPUARMState *env, void *vg, target_ulong addr, + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* Perform gross MTE suppression early. */ +- if (!tbi_check(desc, bit55) || +- tcma_check(desc, bit55, allocation_tag_from_addr(addr))) { ++ if (!tbi_check(mtedesc, bit55) || ++ tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) { + mtedesc = 0; + } + +@@ -6410,8 +6410,8 @@ void sve_stN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr, + desc = extract32(desc, 0, SIMD_DATA_SHIFT + SVE_MTEDESC_SHIFT); + + /* Perform gross MTE suppression early. */ +- if (!tbi_check(desc, bit55) || +- tcma_check(desc, bit55, allocation_tag_from_addr(addr))) { ++ if (!tbi_check(mtedesc, bit55) || ++ tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) { + mtedesc = 0; + } + +-- +1.8.3.1 + diff --git a/0110-target-arm-Don-t-get-MDCR_EL2-in-pmu_counter_enabled.patch b/0110-target-arm-Don-t-get-MDCR_EL2-in-pmu_counter_enabled.patch new file mode 100644 index 0000000000000000000000000000000000000000..7d6bf40a905de3715de8465a4f8691cbafcd50b2 --- /dev/null +++ b/0110-target-arm-Don-t-get-MDCR_EL2-in-pmu_counter_enabled.patch @@ -0,0 +1,71 @@ +From f030e96d27c50a13a5295927d90853680dbc1052 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Thu, 8 Feb 2024 15:33:46 +0000 +Subject: [PATCH 118/293] target/arm: Don't get MDCR_EL2 in + pmu_counter_enabled() before checking ARM_FEATURE_PMU +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It doesn't make sense to read the value of MDCR_EL2 on a non-A-profile +CPU, and in fact if you try to do it we will assert: + +#6 0x00007ffff4b95e96 in __GI___assert_fail + (assertion=0x5555565a8c70 "!arm_feature(env, ARM_FEATURE_M)", file=0x5555565a6e5c "../../target/arm/helper.c", line=12600, function=0x5555565a9560 <__PRETTY_FUNCTION__.0> "arm_security_space_below_el3") at ./assert/assert.c:101 +#7 0x0000555555ebf412 in arm_security_space_below_el3 (env=0x555557bc8190) at ../../target/arm/helper.c:12600 +#8 0x0000555555ea6f89 in arm_is_el2_enabled (env=0x555557bc8190) at ../../target/arm/cpu.h:2595 +#9 0x0000555555ea942f in arm_mdcr_el2_eff (env=0x555557bc8190) at ../../target/arm/internals.h:1512 + +We might call pmu_counter_enabled() on an M-profile CPU (for example +from the migration pre/post hooks in machine.c); this should always +return false because these CPUs don't set ARM_FEATURE_PMU. + +Avoid the assertion by not calling arm_mdcr_el2_eff() before we +have done the early return for "PMU not present". + +This fixes an assertion failure if you try to do a loadvm or +savevm for an M-profile board. + +Cc: qemu-stable@nongnu.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2155 +Signed-off-by: Peter Maydell +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Message-id: 20240208153346.970021-1-peter.maydell@linaro.org +(cherry picked from commit ac1d88e9e7ca0bed83e91e07ce6d0597f10cc77d) +Signed-off-by: Michael Tokarev +--- + target/arm/helper.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 6515c5e..df1646d 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -1169,13 +1169,21 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter) + bool enabled, prohibited = false, filtered; + bool secure = arm_is_secure(env); + int el = arm_current_el(env); +- uint64_t mdcr_el2 = arm_mdcr_el2_eff(env); +- uint8_t hpmn = mdcr_el2 & MDCR_HPMN; ++ uint64_t mdcr_el2; ++ uint8_t hpmn; + ++ /* ++ * We might be called for M-profile cores where MDCR_EL2 doesn't ++ * exist and arm_mdcr_el2_eff() will assert, so this early-exit check ++ * must be before we read that value. ++ */ + if (!arm_feature(env, ARM_FEATURE_PMU)) { + return false; + } + ++ mdcr_el2 = arm_mdcr_el2_eff(env); ++ hpmn = mdcr_el2 & MDCR_HPMN; ++ + if (!arm_feature(env, ARM_FEATURE_EL2) || + (counter < hpmn || counter == 31)) { + e = env->cp15.c9_pmcr & PMCRE; +-- +1.8.3.1 + diff --git a/0111-iotests-Make-144-deterministic-again.patch b/0111-iotests-Make-144-deterministic-again.patch new file mode 100644 index 0000000000000000000000000000000000000000..0b6298d466987f10ad63bfc39efde1f905644107 --- /dev/null +++ b/0111-iotests-Make-144-deterministic-again.patch @@ -0,0 +1,75 @@ +From d5bc76fa20a8887d582710054bb3b06dd80c2aca Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 9 Feb 2024 18:31:03 +0100 +Subject: [PATCH 119/293] iotests: Make 144 deterministic again + +Since commit effd60c8 changed how QMP commands are processed, the order +of the block-commit return value and job events in iotests 144 wasn't +fixed and more and caused the test to fail intermittently. + +Change the test to cache events first and then print them in a +predefined order. + +Waiting three times for JOB_STATUS_CHANGE is a bit uglier than just +waiting for the JOB_STATUS_CHANGE that has "status": "ready", but the +tooling we have doesn't seem to allow the latter easily. + +Fixes: effd60c878176bcaf97fa7ce2b12d04bb8ead6f7 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2126 +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +Message-id: 20240209173103.239994-1-kwolf@redhat.com +Signed-off-by: Peter Maydell +(cherry picked from commit cc29c12ec629ba68a4a6cb7d165c94cc8502815a) +Signed-off-by: Michael Tokarev +--- + tests/qemu-iotests/144 | 12 +++++++++++- + tests/qemu-iotests/144.out | 2 +- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144 +index bdcc498..d284a0e 100755 +--- a/tests/qemu-iotests/144 ++++ b/tests/qemu-iotests/144 +@@ -83,12 +83,22 @@ echo + echo === Performing block-commit on active layer === + echo + ++capture_events="BLOCK_JOB_READY JOB_STATUS_CHANGE" ++ + # Block commit on active layer, push the new overlay into base + _send_qemu_cmd $h "{ 'execute': 'block-commit', + 'arguments': { + 'device': 'virtio0' + } +- }" "READY" ++ }" "return" ++ ++_wait_event $h "JOB_STATUS_CHANGE" ++_wait_event $h "JOB_STATUS_CHANGE" ++_wait_event $h "JOB_STATUS_CHANGE" ++ ++_wait_event $h "BLOCK_JOB_READY" ++ ++capture_events= + + _send_qemu_cmd $h "{ 'execute': 'block-job-complete', + 'arguments': { +diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out +index b3b4812..2245ddf 100644 +--- a/tests/qemu-iotests/144.out ++++ b/tests/qemu-iotests/144.out +@@ -25,9 +25,9 @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off co + 'device': 'virtio0' + } + } ++{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "virtio0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "virtio0"}} +-{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "virtio0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} + { 'execute': 'block-job-complete', +-- +1.8.3.1 + diff --git a/0112-.gitlab-ci-windows.yml-Don-t-install-libusb-or-spice.patch b/0112-.gitlab-ci-windows.yml-Don-t-install-libusb-or-spice.patch new file mode 100644 index 0000000000000000000000000000000000000000..d23b30feda26a0608333e598ab6ea814d5b4986b --- /dev/null +++ b/0112-.gitlab-ci-windows.yml-Don-t-install-libusb-or-spice.patch @@ -0,0 +1,82 @@ +From 4d9dc117eae8a5d5464635a436349c71e2f8ce8d Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Thu, 15 Feb 2024 15:50:09 +0000 +Subject: [PATCH 120/293] .gitlab-ci/windows.yml: Don't install libusb or spice + packages on 32-bit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When msys2 updated their libusb packages to libusb 1.0.27, they +dropped support for building them for mingw32, leaving only mingw64 +packages. This broke our CI job, as the 'pacman' package install now +fails with: + +error: target not found: mingw-w64-i686-libusb +error: target not found: mingw-w64-i686-usbredir + +(both these binary packages are from the libusb source package). + +Similarly, spice is now 64-bit only: +error: target not found: mingw-w64-i686-spice + +Fix this by dropping these packages from the list we install for our +msys2-32bit build. We do this with a simple mechanism for the +msys2-64bit and msys2-32bit jobs to specify a list of extra packages +to install on top of the common ones we install for both jobs. + +Cc: qemu-stable@nongnu.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2160 +Signed-off-by: Peter Maydell +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Michael Tokarev +Message-id: 20240215155009.2422335-1-peter.maydell@linaro.org +(cherry picked from commit 8e31b744fdf2c5d933681e4128acee72a83af4b8) +Signed-off-by: Michael Tokarev +--- + .gitlab-ci.d/windows.yml | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml +index f7645f7..5c1e385 100644 +--- a/.gitlab-ci.d/windows.yml ++++ b/.gitlab-ci.d/windows.yml +@@ -88,7 +88,6 @@ + $MINGW_TARGET-libpng + $MINGW_TARGET-libssh + $MINGW_TARGET-libtasn1 +- $MINGW_TARGET-libusb + $MINGW_TARGET-lzo2 + $MINGW_TARGET-nettle + $MINGW_TARGET-ninja +@@ -98,9 +97,8 @@ + $MINGW_TARGET-SDL2 + $MINGW_TARGET-SDL2_image + $MINGW_TARGET-snappy +- $MINGW_TARGET-spice +- $MINGW_TARGET-usbredir +- $MINGW_TARGET-zstd " ++ $MINGW_TARGET-zstd ++ $EXTRA_PACKAGES " + - Write-Output "Running build at $(Get-Date -Format u)" + - $env:CHERE_INVOKING = 'yes' # Preserve the current working directory + - $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink +@@ -123,6 +121,8 @@ msys2-64bit: + variables: + MINGW_TARGET: mingw-w64-x86_64 + MSYSTEM: MINGW64 ++ # msys2 only ship these packages for 64-bit, not 32-bit ++ EXTRA_PACKAGES: $MINGW_TARGET-libusb $MINGW_TARGET-usbredir $MINGW_TARGET-spice + # do not remove "--without-default-devices"! + # commit 9f8e6cad65a6 ("gitlab-ci: Speed up the msys2-64bit job by using --without-default-devices" + # changed to compile QEMU with the --without-default-devices switch +@@ -137,5 +137,6 @@ msys2-32bit: + variables: + MINGW_TARGET: mingw-w64-i686 + MSYSTEM: MINGW32 ++ EXTRA_PACKAGES: + CONFIGURE_ARGS: --target-list=ppc64-softmmu -Ddebug=false -Doptimization=0 + TEST_ARGS: --no-suite qtest +-- +1.8.3.1 + diff --git a/1001-i386-cpu-Clear-FEAT_XSAVE_XSS_LO-HI-leafs-when-CPUID.patch b/0113-i386-cpu-Clear-FEAT_XSAVE_XSS_LO-HI-leafs-when-CPUID.patch similarity index 69% rename from 1001-i386-cpu-Clear-FEAT_XSAVE_XSS_LO-HI-leafs-when-CPUID.patch rename to 0113-i386-cpu-Clear-FEAT_XSAVE_XSS_LO-HI-leafs-when-CPUID.patch index 7709d6ec139a69acc9e6e183428117da8b627e95..1385926ca05442aef2e59b21267ae6cfd3d86c03 100644 --- a/1001-i386-cpu-Clear-FEAT_XSAVE_XSS_LO-HI-leafs-when-CPUID.patch +++ b/0113-i386-cpu-Clear-FEAT_XSAVE_XSS_LO-HI-leafs-when-CPUID.patch @@ -1,31 +1,26 @@ -From 15c883697908b38e9021277d83480d382fc76b3a Mon Sep 17 00:00:00 2001 +From 0766f137f50068e73fdca2a23b6f7b1de23d83ef Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Mon, 15 Jan 2024 04:13:24 -0500 -Subject: [PATCH] i386/cpu: Clear FEAT_XSAVE_XSS_LO/HI leafs when +Subject: [PATCH 121/293] i386/cpu: Clear FEAT_XSAVE_XSS_LO/HI leafs when CPUID_EXT_XSAVE is not available -commit 81f5cad3858f27623b1b14467926032d229b76cc upstream. - Leaf FEAT_XSAVE_XSS_LO and FEAT_XSAVE_XSS_HI also need to be cleared when CPUID_EXT_XSAVE is not set. -Intel-SIG: commit 81f5cad3858f i386/cpu: Clear FEAT_XSAVE_XSS_LO/HI leafs when CPUID_EXT_XSAVE is not available -Backport i386/cpu fixes - Fixes: 301e90675c3f ("target/i386: Enable support for XSAVES based features") Signed-off-by: Xiaoyao Li Reviewed-by: Yang Weijiang Message-ID: <20240115091325.1904229-2-xiaoyao.li@intel.com> Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini -Signed-off-by: Jason Zeng -Signed-off-by: Aubrey Li +(cherry picked from commit 81f5cad3858f27623b1b14467926032d229b76cc) +Signed-off-by: Michael Tokarev --- target/i386/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index cd16cb893daf..8b9ef218d3df 100644 +index cd16cb8..8b9ef21 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6927,6 +6927,8 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) @@ -38,5 +33,5 @@ index cd16cb893daf..8b9ef218d3df 100644 } -- -2.34.1 +1.8.3.1 diff --git a/1002-i386-cpu-Mask-with-XCR0-XSS-mask-for-FEAT_XSAVE_XCR0.patch b/0114-i386-cpu-Mask-with-XCR0-XSS-mask-for-FEAT_XSAVE_XCR0.patch similarity index 71% rename from 1002-i386-cpu-Mask-with-XCR0-XSS-mask-for-FEAT_XSAVE_XCR0.patch rename to 0114-i386-cpu-Mask-with-XCR0-XSS-mask-for-FEAT_XSAVE_XCR0.patch index fbefa7fdfbf87fd4844368e870cf4f75eb69d8c1..365ebd777c71d621679b74dad05458c2a7ca091e 100644 --- a/1002-i386-cpu-Mask-with-XCR0-XSS-mask-for-FEAT_XSAVE_XCR0.patch +++ b/0114-i386-cpu-Mask-with-XCR0-XSS-mask-for-FEAT_XSAVE_XCR0.patch @@ -1,32 +1,27 @@ -From 626266a79b8e4826c185e94ca2fc339a304a21ca Mon Sep 17 00:00:00 2001 +From 72c4ef9da08c4e8c692fe429cfd78ec934cdfb84 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Mon, 15 Jan 2024 04:13:25 -0500 -Subject: [PATCH] i386/cpu: Mask with XCR0/XSS mask for FEAT_XSAVE_XCR0_HI and - FEAT_XSAVE_XSS_HI leafs - -commit a11a365159b944e05be76f3ec3b98c8b38cb70fd upstream. +Subject: [PATCH 122/293] i386/cpu: Mask with XCR0/XSS mask for + FEAT_XSAVE_XCR0_HI and FEAT_XSAVE_XSS_HI leafs The value of FEAT_XSAVE_XCR0_HI leaf and FEAT_XSAVE_XSS_HI leaf also need to be masked by XCR0 and XSS mask respectively, to make it logically correct. -Intel-SIG: commit a11a365159b9 i386/cpu: Mask with XCR0/XSS mask for FEAT_XSAVE_XCR0_HI and FEAT_XSAVE_XSS_HI leafs -Backport i386/cpu fixes - Fixes: 301e90675c3f ("target/i386: Enable support for XSAVES based features") Signed-off-by: Xiaoyao Li Reviewed-by: Yang Weijiang Message-ID: <20240115091325.1904229-3-xiaoyao.li@intel.com> Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini -Signed-off-by: Jason Zeng -Signed-off-by: Aubrey Li +(cherry picked from commit a11a365159b944e05be76f3ec3b98c8b38cb70fd) +Signed-off-by: Michael Tokarev --- target/i386/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 8b9ef218d3df..a66e5a357b19 100644 +index 8b9ef21..a66e5a3 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6947,9 +6947,9 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) @@ -42,5 +37,5 @@ index 8b9ef218d3df..a66e5a357b19 100644 /***** Steps involved on loading and filtering CPUID data -- -2.34.1 +1.8.3.1 diff --git a/1003-i386-cpuid-Decrease-cpuid_i-when-skipping-CPUID-leaf.patch b/0115-i386-cpuid-Decrease-cpuid_i-when-skipping-CPUID-leaf.patch similarity index 67% rename from 1003-i386-cpuid-Decrease-cpuid_i-when-skipping-CPUID-leaf.patch rename to 0115-i386-cpuid-Decrease-cpuid_i-when-skipping-CPUID-leaf.patch index ba00a2d200607973be16003455ec3fa095b4f500..28c29cbf95bb8d8f5a8b14d2f5e797b549510efc 100644 --- a/1003-i386-cpuid-Decrease-cpuid_i-when-skipping-CPUID-leaf.patch +++ b/0115-i386-cpuid-Decrease-cpuid_i-when-skipping-CPUID-leaf.patch @@ -1,9 +1,8 @@ -From 2bb1c3d8c6d669468c574db017c96df17e797dc9 Mon Sep 17 00:00:00 2001 +From e8d27721cbb267fde6b7ce7e0984ec07df21d7e7 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Wed, 24 Jan 2024 21:40:14 -0500 -Subject: [PATCH] i386/cpuid: Decrease cpuid_i when skipping CPUID leaf 1F - -commit 10f92799af8ba3c3cef2352adcd4780f13fbab31 upstream. +Subject: [PATCH 123/293] i386/cpuid: Decrease cpuid_i when skipping CPUID leaf + 1F Existing code misses a decrement of cpuid_i when skip leaf 0x1F. There's a blank CPUID entry(with leaf, subleaf as 0, and all fields @@ -11,22 +10,19 @@ stuffed 0s) left in the CPUID array. It conflicts with correct CPUID leaf 0. -Intel-SIG: commit 10f92799af8b i386/cpuid: Decrease cpuid_i when skipping CPUID leaf 1F -Backport i386/cpuid fixes - Signed-off-by: Xiaoyao Li Reviewed-by:Yang Weijiang Message-ID: <20240125024016.2521244-2-xiaoyao.li@intel.com> Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini -Signed-off-by: Jason Zeng -Signed-off-by: Aubrey Li +(cherry picked from commit 10f92799af8ba3c3cef2352adcd4780f13fbab31) +Signed-off-by: Michael Tokarev --- target/i386/kvm/kvm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 4ce80555b45c..e68eb8f5e6b0 100644 +index 4ce8055..e68eb8f 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1914,6 +1914,7 @@ int kvm_arch_init_vcpu(CPUState *cs) @@ -38,5 +34,5 @@ index 4ce80555b45c..e68eb8f5e6b0 100644 } /* fallthrough */ -- -2.34.1 +1.8.3.1 diff --git a/1004-i386-cpuid-Move-leaf-7-to-correct-group.patch b/0116-i386-cpuid-Move-leaf-7-to-correct-group.patch similarity index 76% rename from 1004-i386-cpuid-Move-leaf-7-to-correct-group.patch rename to 0116-i386-cpuid-Move-leaf-7-to-correct-group.patch index 659f0efbf97034fa5a2ed084b056e298aba6dd98..fe4047189e1f4fe01d095fc51f8ac119f3b84fe1 100644 --- a/1004-i386-cpuid-Move-leaf-7-to-correct-group.patch +++ b/0116-i386-cpuid-Move-leaf-7-to-correct-group.patch @@ -1,9 +1,7 @@ -From 6449fc40100be71bdb454f542ca708026cd5ad11 Mon Sep 17 00:00:00 2001 +From f5dddb856cccdc491547235aeafb451acd63c8b1 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Wed, 24 Jan 2024 21:40:16 -0500 -Subject: [PATCH] i386/cpuid: Move leaf 7 to correct group - -commit 0729857c707535847d7fe31d3d91eb8b2a118e3c upstream. +Subject: [PATCH 124/293] i386/cpuid: Move leaf 7 to correct group CPUID leaf 7 was grouped together with SGX leaf 0x12 by commit b9edbadefb9e ("i386: Propagate SGX CPUID sub-leafs to KVM") by mistake. @@ -15,22 +13,19 @@ not. Leaf 7 follows the logic that EAX of subleaf 0 enumerates the maximum valid subleaf. -Intel-SIG: commit 0729857c7075 i386/cpuid: Move leaf 7 to correct group -Backport i386/cpu fixes - Fixes: b9edbadefb9e ("i386: Propagate SGX CPUID sub-leafs to KVM") Signed-off-by: Xiaoyao Li Message-ID: <20240125024016.2521244-4-xiaoyao.li@intel.com> Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini -Signed-off-by: Jason Zeng -Signed-off-by: Aubrey Li +(cherry picked from commit 0729857c707535847d7fe31d3d91eb8b2a118e3c) +Signed-off-by: Michael Tokarev --- target/i386/kvm/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index e68eb8f5e6b0..a0bc9ea7b192 100644 +index e68eb8f..a0bc9ea 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1955,7 +1955,6 @@ int kvm_arch_init_vcpu(CPUState *cs) @@ -50,5 +45,5 @@ index e68eb8f5e6b0..a0bc9ea7b192 100644 case 0x1d: case 0x1e: { -- -2.34.1 +1.8.3.1 diff --git a/0117-target-i386-Generate-an-illegal-opcode-exception-on-.patch b/0117-target-i386-Generate-an-illegal-opcode-exception-on-.patch new file mode 100644 index 0000000000000000000000000000000000000000..9bc5c17d4b9582c9f902d2776a3c3faf200b71b6 --- /dev/null +++ b/0117-target-i386-Generate-an-illegal-opcode-exception-on-.patch @@ -0,0 +1,46 @@ +From 0b30735d3807640587c2bc9b19ab274e0f8eef57 Mon Sep 17 00:00:00 2001 +From: Ziqiao Kong +Date: Thu, 15 Feb 2024 17:50:17 +0800 +Subject: [PATCH 125/293] target/i386: Generate an illegal opcode exception on + cmp instructions with lock prefix + +target/i386: As specified by Intel Manual Vol2 3-180, cmp instructions +are not allowed to have lock prefix and a `UD` should be raised. Without +this patch, s1->T0 will be uninitialized and used in the case OP_CMPL. + +Signed-off-by: Ziqiao Kong +Message-ID: <20240215095015.570748-2-ziqiaokong@gmail.com> +Cc: qemu-stable@nongnu.org +Signed-off-by: Paolo Bonzini +(cherry picked from commit 99d0dcd7f102c07a510200d768cae65e5db25d23) +Signed-off-by: Michael Tokarev +--- + target/i386/tcg/translate.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c +index 8fd49ff..83c2b40 100644 +--- a/target/i386/tcg/translate.c ++++ b/target/i386/tcg/translate.c +@@ -1480,12 +1480,13 @@ static bool check_iopl(DisasContext *s) + /* if d == OR_TMP0, it means memory operand (address in A0) */ + static void gen_op(DisasContext *s1, int op, MemOp ot, int d) + { ++ /* Invalid lock prefix when destination is not memory or OP_CMPL. */ ++ if ((d != OR_TMP0 || op == OP_CMPL) && s1->prefix & PREFIX_LOCK) { ++ gen_illegal_opcode(s1); ++ return; ++ } ++ + if (d != OR_TMP0) { +- if (s1->prefix & PREFIX_LOCK) { +- /* Lock prefix when destination is not memory. */ +- gen_illegal_opcode(s1); +- return; +- } + gen_op_mov_v_reg(s1, ot, s1->T0, d); + } else if (!(s1->prefix & PREFIX_LOCK)) { + gen_op_ld_v(s1, ot, s1->T0, s1->A0); +-- +1.8.3.1 + diff --git a/0118-ui-reject-extended-clipboard-message-if-not-activate.patch b/0118-ui-reject-extended-clipboard-message-if-not-activate.patch new file mode 100644 index 0000000000000000000000000000000000000000..802475a566bc140cad8f699516b8f6e6a9ab6515 --- /dev/null +++ b/0118-ui-reject-extended-clipboard-message-if-not-activate.patch @@ -0,0 +1,42 @@ +From 4fd56da3370a7ad009a0a960e722991c9927d890 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Mon, 15 Jan 2024 09:51:19 +0000 +Subject: [PATCH 126/293] ui: reject extended clipboard message if not + activated +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The extended clipboard message protocol requires that the client +activate the extension by requesting a psuedo encoding. If this +is not done, then any extended clipboard messages from the client +should be considered invalid and the client dropped. + +Signed-off-by: Daniel P. Berrangé +Reviewed-by: Marc-André Lureau +Message-Id: <20240115095119.654271-1-berrange@redhat.com> +(cherry picked from commit 4cba8388968b70fe20e290221dc421c717051fdd) +Signed-off-by: Michael Tokarev +--- + ui/vnc.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 4f23a0f..3b2c71e 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -2445,6 +2445,11 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) + } + + if (read_s32(data, 4) < 0) { ++ if (!vnc_has_feature(vs, VNC_FEATURE_CLIPBOARD_EXT)) { ++ error_report("vnc: extended clipboard message while disabled"); ++ vnc_client_error(vs); ++ break; ++ } + if (dlen < 4) { + error_report("vnc: malformed payload (header less than 4 bytes)" + " in extended clipboard pseudo-encoding."); +-- +1.8.3.1 + diff --git a/0119-ui-clipboard-mark-type-as-not-available-when-there-i.patch b/0119-ui-clipboard-mark-type-as-not-available-when-there-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..cead25ec5c3d40d8a0377cc6f04ca006dc5bf1ba --- /dev/null +++ b/0119-ui-clipboard-mark-type-as-not-available-when-there-i.patch @@ -0,0 +1,90 @@ +From 480a6adc83a7bbc84bfe67229e084603dc061824 Mon Sep 17 00:00:00 2001 +From: Fiona Ebner +Date: Wed, 24 Jan 2024 11:57:48 +0100 +Subject: [PATCH 127/293] ui/clipboard: mark type as not available when there + is no data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With VNC, a client can send a non-extended VNC_MSG_CLIENT_CUT_TEXT +message with len=0. In qemu_clipboard_set_data(), the clipboard info +will be updated setting data to NULL (because g_memdup(data, size) +returns NULL when size is 0). If the client does not set the +VNC_ENCODING_CLIPBOARD_EXT feature when setting up the encodings, then +the 'request' callback for the clipboard peer is not initialized. +Later, because data is NULL, qemu_clipboard_request() can be reached +via vdagent_chr_write() and vdagent_clipboard_recv_request() and +there, the clipboard owner's 'request' callback will be attempted to +be called, but that is a NULL pointer. + +In particular, this can happen when using the KRDC (22.12.3) VNC +client. + +Another scenario leading to the same issue is with two clients (say +noVNC and KRDC): + +The noVNC client sets the extension VNC_FEATURE_CLIPBOARD_EXT and +initializes its cbpeer. + +The KRDC client does not, but triggers a vnc_client_cut_text() (note +it's not the _ext variant)). There, a new clipboard info with it as +the 'owner' is created and via qemu_clipboard_set_data() is called, +which in turn calls qemu_clipboard_update() with that info. + +In qemu_clipboard_update(), the notifier for the noVNC client will be +called, i.e. vnc_clipboard_notify() and also set vs->cbinfo for the +noVNC client. The 'owner' in that clipboard info is the clipboard peer +for the KRDC client, which did not initialize the 'request' function. +That sounds correct to me, it is the owner of that clipboard info. + +Then when noVNC sends a VNC_MSG_CLIENT_CUT_TEXT message (it did set +the VNC_FEATURE_CLIPBOARD_EXT feature correctly, so a check for it +passes), that clipboard info is passed to qemu_clipboard_request() and +the original segfault still happens. + +Fix the issue by handling updates with size 0 differently. In +particular, mark in the clipboard info that the type is not available. + +While at it, switch to g_memdup2(), because g_memdup() is deprecated. + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2023-6683 +Reported-by: Markus Frank +Suggested-by: Marc-André Lureau +Signed-off-by: Fiona Ebner +Reviewed-by: Marc-André Lureau +Tested-by: Markus Frank +Message-ID: <20240124105749.204610-1-f.ebner@proxmox.com> +(cherry picked from commit 405484b29f6548c7b86549b0f961b906337aa68a) +Signed-off-by: Michael Tokarev +--- + ui/clipboard.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/ui/clipboard.c b/ui/clipboard.c +index 3d14bff..b3f6fa3 100644 +--- a/ui/clipboard.c ++++ b/ui/clipboard.c +@@ -163,9 +163,15 @@ void qemu_clipboard_set_data(QemuClipboardPeer *peer, + } + + g_free(info->types[type].data); +- info->types[type].data = g_memdup(data, size); +- info->types[type].size = size; +- info->types[type].available = true; ++ if (size) { ++ info->types[type].data = g_memdup2(data, size); ++ info->types[type].size = size; ++ info->types[type].available = true; ++ } else { ++ info->types[type].data = NULL; ++ info->types[type].size = 0; ++ info->types[type].available = false; ++ } + + if (update) { + qemu_clipboard_update(info); +-- +1.8.3.1 + diff --git a/0120-ui-clipboard-add-asserts-for-update-and-request.patch b/0120-ui-clipboard-add-asserts-for-update-and-request.patch new file mode 100644 index 0000000000000000000000000000000000000000..064aeec63a393a1779db91d7a83519224758fc52 --- /dev/null +++ b/0120-ui-clipboard-add-asserts-for-update-and-request.patch @@ -0,0 +1,62 @@ +From 7ff0d4d184a83ac54b917c5af577e7a32e6a6f3e Mon Sep 17 00:00:00 2001 +From: Fiona Ebner +Date: Wed, 24 Jan 2024 11:57:49 +0100 +Subject: [PATCH 128/293] ui/clipboard: add asserts for update and request +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Should an issue like CVE-2023-6683 ever appear again in the future, +it will be more obvious which assumption was violated. + +Suggested-by: Marc-André Lureau +Signed-off-by: Fiona Ebner +Reviewed-by: Marc-André Lureau +Message-ID: <20240124105749.204610-2-f.ebner@proxmox.com> +(cherry picked from commit 9c416582611b7495bdddb4c5456c7acb64b78938) +Signed-off-by: Michael Tokarev +--- + ui/clipboard.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/ui/clipboard.c b/ui/clipboard.c +index b3f6fa3..4264884 100644 +--- a/ui/clipboard.c ++++ b/ui/clipboard.c +@@ -65,12 +65,24 @@ bool qemu_clipboard_check_serial(QemuClipboardInfo *info, bool client) + + void qemu_clipboard_update(QemuClipboardInfo *info) + { ++ uint32_t type; + QemuClipboardNotify notify = { + .type = QEMU_CLIPBOARD_UPDATE_INFO, + .info = info, + }; + assert(info->selection < QEMU_CLIPBOARD_SELECTION__COUNT); + ++ for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) { ++ /* ++ * If data is missing, the clipboard owner's 'request' callback needs to ++ * be set. Otherwise, there is no way to get the clipboard data and ++ * qemu_clipboard_request() cannot be called. ++ */ ++ if (info->types[type].available && !info->types[type].data) { ++ assert(info->owner && info->owner->request); ++ } ++ } ++ + notifier_list_notify(&clipboard_notifiers, ¬ify); + + if (cbinfo[info->selection] != info) { +@@ -132,6 +144,8 @@ void qemu_clipboard_request(QemuClipboardInfo *info, + !info->owner) + return; + ++ assert(info->owner->request); ++ + info->types[type].requested = true; + info->owner->request(info, type); + } +-- +1.8.3.1 + diff --git a/0121-ui-console-Fix-console-resize-with-placeholder-surfa.patch b/0121-ui-console-Fix-console-resize-with-placeholder-surfa.patch new file mode 100644 index 0000000000000000000000000000000000000000..e9cdaf9d982bc8187b362d732c9c75a12f22aedb --- /dev/null +++ b/0121-ui-console-Fix-console-resize-with-placeholder-surfa.patch @@ -0,0 +1,43 @@ +From 2e5c9d5462a24d54ed8df0fcbab12e3cc6b50f90 Mon Sep 17 00:00:00 2001 +From: Tianlan Zhou +Date: Thu, 8 Feb 2024 01:20:25 +0800 +Subject: [PATCH 129/293] ui/console: Fix console resize with placeholder + surface +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In `qemu_console_resize()`, the old surface of the console is keeped if the new +console size is the same as the old one. If the old surface is a placeholder, +and the new size of console is the same as the placeholder surface (640*480), +the surface won't be replace. +In this situation, the surface's `QEMU_PLACEHOLDER_FLAG` flag is still set, so +the console won't be displayed in SDL display mode. +This patch fixes this problem by forcing a new surface if the old one is a +placeholder. + +Signed-off-by: Tianlan Zhou +Reviewed-by: Marc-André Lureau +Message-ID: <20240207172024.8-1-bobby825@126.com> +(cherry picked from commit 95b08fee8f68d284a5028d37fd28be7a70c8e92b) +Signed-off-by: Michael Tokarev +--- + ui/console.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ui/console.c b/ui/console.c +index 7db921e..83205567 100644 +--- a/ui/console.c ++++ b/ui/console.c +@@ -1577,7 +1577,7 @@ void qemu_console_resize(QemuConsole *s, int width, int height) + assert(QEMU_IS_GRAPHIC_CONSOLE(s)); + + if ((s->scanout.kind != SCANOUT_SURFACE || +- (surface && surface->flags & QEMU_ALLOCATED_FLAG)) && ++ (surface && !is_buffer_shared(surface) && !is_placeholder(surface))) && + qemu_console_get_width(s, -1) == width && + qemu_console_get_height(s, -1) == height) { + return; +-- +1.8.3.1 + diff --git a/0122-audio-Depend-on-dbus_display1_dep.patch b/0122-audio-Depend-on-dbus_display1_dep.patch new file mode 100644 index 0000000000000000000000000000000000000000..38c7a821dc02956486d28aab2223b6a260573dad --- /dev/null +++ b/0122-audio-Depend-on-dbus_display1_dep.patch @@ -0,0 +1,37 @@ +From 1766b9360c3dfe3fb18241149047dc369ff7b1ae Mon Sep 17 00:00:00 2001 +From: Akihiko Odaki +Date: Wed, 14 Feb 2024 23:03:56 +0900 +Subject: [PATCH 130/293] audio: Depend on dbus_display1_dep +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +dbusaudio needs dbus_display1_dep. + +Fixes: 739362d4205c ("audio: add "dbus" audio backend") +Signed-off-by: Akihiko Odaki +Reviewed-by: Marc-André Lureau +Message-Id: <20240214-dbus-v7-1-7eff29f04c34@daynix.com> +(cherry picked from commit d67611907590a1e6c998b7c5a5cb4394acf84329) +Signed-off-by: Michael Tokarev +--- + audio/meson.build | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/audio/meson.build b/audio/meson.build +index c8f6586..608f35e 100644 +--- a/audio/meson.build ++++ b/audio/meson.build +@@ -30,7 +30,8 @@ endforeach + + if dbus_display + module_ss = ss.source_set() +- module_ss.add(when: [gio, pixman], if_true: files('dbusaudio.c')) ++ module_ss.add(when: [gio, dbus_display1_dep, pixman], ++ if_true: files('dbusaudio.c')) + audio_modules += {'dbus': module_ss} + endif + +-- +1.8.3.1 + diff --git a/0123-meson-Explicitly-specify-dbus-display1.h-dependency.patch b/0123-meson-Explicitly-specify-dbus-display1.h-dependency.patch new file mode 100644 index 0000000000000000000000000000000000000000..ed9910d7a425d4d18c564db8a4ea9116065e184b --- /dev/null +++ b/0123-meson-Explicitly-specify-dbus-display1.h-dependency.patch @@ -0,0 +1,37 @@ +From fb22ee75b2949b57c18872f9d1b026af9f068455 Mon Sep 17 00:00:00 2001 +From: Akihiko Odaki +Date: Wed, 14 Feb 2024 23:03:57 +0900 +Subject: [PATCH 131/293] meson: Explicitly specify dbus-display1.h dependency +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Explicitly specify dbus-display1.h as a dependency so that files +depending on it will not get compiled too early. + +Fixes: 1222070e7728 ("meson: ensure dbus-display generated code is built before other units") +Signed-off-by: Akihiko Odaki +Reviewed-by: Marc-André Lureau +Message-Id: <20240214-dbus-v7-2-7eff29f04c34@daynix.com> +(cherry picked from commit 7aee57df930da2cf6361c5183aff96468ae4027d) +Signed-off-by: Michael Tokarev +--- + ui/meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ui/meson.build b/ui/meson.build +index 0ccb338..0f09d31 100644 +--- a/ui/meson.build ++++ b/ui/meson.build +@@ -92,7 +92,7 @@ if dbus_display + '--c-namespace', 'QemuDBus', + '--generate-c-code', '@BASENAME@']) + dbus_display1_lib = static_library('dbus-display1', dbus_display1, dependencies: gio) +- dbus_display1_dep = declare_dependency(link_with: dbus_display1_lib, include_directories: include_directories('.')) ++ dbus_display1_dep = declare_dependency(link_with: dbus_display1_lib, sources: dbus_display1[0]) + dbus_ss.add(when: [gio, dbus_display1_dep], + if_true: [files( + 'dbus-chardev.c', +-- +1.8.3.1 + diff --git a/0124-tests-qtest-Depend-on-dbus_display1_dep.patch b/0124-tests-qtest-Depend-on-dbus_display1_dep.patch new file mode 100644 index 0000000000000000000000000000000000000000..202d0e2e67a20c48bd845bb92d0cd45b94871f39 --- /dev/null +++ b/0124-tests-qtest-Depend-on-dbus_display1_dep.patch @@ -0,0 +1,35 @@ +From 814f887430deb390341c8585cd413e0effc94798 Mon Sep 17 00:00:00 2001 +From: Akihiko Odaki +Date: Wed, 14 Feb 2024 23:03:58 +0900 +Subject: [PATCH 132/293] tests/qtest: Depend on dbus_display1_dep +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It ensures dbus-display1.c will not be recompiled. + +Signed-off-by: Akihiko Odaki +Reviewed-by: Marc-André Lureau +Message-Id: <20240214-dbus-v7-3-7eff29f04c34@daynix.com> +(cherry picked from commit 186acfbaf7f325833702f50f75ef5116dc29e233) +Signed-off-by: Michael Tokarev +--- + tests/qtest/meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build +index fc14ae9..f096cf3 100644 +--- a/tests/qtest/meson.build ++++ b/tests/qtest/meson.build +@@ -333,7 +333,7 @@ if vnc.found() + endif + + if dbus_display +- qtests += {'dbus-display-test': [dbus_display1, gio]} ++ qtests += {'dbus-display-test': [dbus_display1_dep, gio]} + endif + + qtest_executables = {} +-- +1.8.3.1 + diff --git a/0125-hw-hppa-Kconfig-Fix-building-with-configure-without-.patch b/0125-hw-hppa-Kconfig-Fix-building-with-configure-without-.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7b1e5de3460fcaae5c25d01d77b111a0126772a --- /dev/null +++ b/0125-hw-hppa-Kconfig-Fix-building-with-configure-without-.patch @@ -0,0 +1,55 @@ +From 56ee4a67cbfcc1f0c8dab0a9fd8d09dc9cd5a1c8 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Fri, 16 Feb 2024 10:16:21 +0100 +Subject: [PATCH 133/293] hw/hppa/Kconfig: Fix building with "configure + --without-default-devices" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When running "configure" with "--without-default-devices", building +of qemu-system-hppa currently fails with: + + /usr/bin/ld: libqemu-hppa-softmmu.fa.p/hw_hppa_machine.c.o: in function `machine_HP_common_init_tail': + hw/hppa/machine.c:399: undefined reference to `usb_bus_find' + /usr/bin/ld: hw/hppa/machine.c:399: undefined reference to `usb_create_simple' + /usr/bin/ld: hw/hppa/machine.c:400: undefined reference to `usb_bus_find' + /usr/bin/ld: hw/hppa/machine.c:400: undefined reference to `usb_create_simple' + collect2: error: ld returned 1 exit status + ninja: build stopped: subcommand failed. + make: *** [Makefile:162: run-ninja] Error 1 + +And after fixing this, the qemu-system-hppa binary refuses to run +due to the missing 'pci-ohci' and 'pci-serial' devices. Let's add +the right config switches to fix these problems. + +Signed-off-by: Thomas Huth +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Michael Tokarev +Signed-off-by: Michael Tokarev +(cherry picked from commit 04b86ccb5dc8a1fad809753cfbaafd4bb13283d4) +Signed-off-by: Michael Tokarev +--- + hw/hppa/Kconfig | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/hppa/Kconfig b/hw/hppa/Kconfig +index ff8528a..dff5df7 100644 +--- a/hw/hppa/Kconfig ++++ b/hw/hppa/Kconfig +@@ -7,6 +7,7 @@ config HPPA_B160L + select DINO + select LASI + select SERIAL ++ select SERIAL_PCI + select ISA_BUS + select I8259 + select IDE_CMD646 +@@ -16,3 +17,4 @@ config HPPA_B160L + select LASIPS2 + select PARALLEL + select ARTIST ++ select USB_OHCI_PCI +-- +1.8.3.1 + diff --git a/0126-docs-system-Update-description-for-input-grab-key.patch b/0126-docs-system-Update-description-for-input-grab-key.patch new file mode 100644 index 0000000000000000000000000000000000000000..325833f50d3935976d3804df14a933ba7ac33135 --- /dev/null +++ b/0126-docs-system-Update-description-for-input-grab-key.patch @@ -0,0 +1,34 @@ +From 2da2e679d6f6aa43521acf1fb3e35799baa44d80 Mon Sep 17 00:00:00 2001 +From: Tianlan Zhou +Date: Thu, 22 Feb 2024 03:52:09 +0800 +Subject: [PATCH 134/293] docs/system: Update description for input grab key + +Input grab key should be Ctrl-Alt-g, not just Ctrl-Alt. + +Fixes: f8d2c9369b ("sdl: use ctrl-alt-g as grab hotkey") +Signed-off-by: Tianlan Zhou +Reviewed-by: Thomas Huth +Reviewed-by: Michael Tokarev +Signed-off-by: Michael Tokarev +(cherry picked from commit 4a20ac400ff0753f159071764826b20e5320cde9) +Signed-off-by: Michael Tokarev +--- + docs/system/keys.rst.inc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/system/keys.rst.inc b/docs/system/keys.rst.inc +index 2e2c97a..59966a3 100644 +--- a/docs/system/keys.rst.inc ++++ b/docs/system/keys.rst.inc +@@ -29,7 +29,7 @@ Ctrl-Alt-n + *3* + Serial port + +-Ctrl-Alt ++Ctrl-Alt-g + Toggle mouse and keyboard grab. + + In the virtual consoles, you can use Ctrl-Up, Ctrl-Down, Ctrl-PageUp and +-- +1.8.3.1 + diff --git a/0127-system-vl-Update-description-for-input-grab-key.patch b/0127-system-vl-Update-description-for-input-grab-key.patch new file mode 100644 index 0000000000000000000000000000000000000000..39c0e6fafd553c09dc7baa17fe22e83c8b514d4c --- /dev/null +++ b/0127-system-vl-Update-description-for-input-grab-key.patch @@ -0,0 +1,34 @@ +From aafe8c0d12b0449b0565d8ce8112e16f4ddd3ca1 Mon Sep 17 00:00:00 2001 +From: Tianlan Zhou +Date: Thu, 22 Feb 2024 03:52:10 +0800 +Subject: [PATCH 135/293] system/vl: Update description for input grab key + +Input grab key should be Ctrl-Alt-g, not just Ctrl-Alt. + +Fixes: f8d2c9369b ("sdl: use ctrl-alt-g as grab hotkey") +Signed-off-by: Tianlan Zhou +Reviewed-by: Thomas Huth +Reviewed-by: Michael Tokarev +Signed-off-by: Michael Tokarev +(cherry picked from commit 185311130f54ead75c407cdf83004d575829b5d2) +Signed-off-by: Michael Tokarev +--- + system/vl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/system/vl.c b/system/vl.c +index 938b7b5..e18fa3c 100644 +--- a/system/vl.c ++++ b/system/vl.c +@@ -892,7 +892,7 @@ static void help(int exitcode) + printf("\nDuring emulation, the following keys are useful:\n" + "ctrl-alt-f toggle full screen\n" + "ctrl-alt-n switch to virtual console 'n'\n" +- "ctrl-alt toggle mouse and keyboard grab\n" ++ "ctrl-alt-g toggle mouse and keyboard grab\n" + "\n" + "When using -nographic, press 'ctrl-a h' to get some help.\n" + "\n" +-- +1.8.3.1 + diff --git a/0128-.gitlab-ci.d-windows.yml-Drop-msys2-32bit-job.patch b/0128-.gitlab-ci.d-windows.yml-Drop-msys2-32bit-job.patch new file mode 100644 index 0000000000000000000000000000000000000000..61b19a4059ccd91dccbde444658d795f80e70bf4 --- /dev/null +++ b/0128-.gitlab-ci.d-windows.yml-Drop-msys2-32bit-job.patch @@ -0,0 +1,57 @@ +From 01aa603fb1083da1e26f5ce548a2ab64c21e8f50 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Tue, 20 Feb 2024 16:56:02 +0000 +Subject: [PATCH 136/293] .gitlab-ci.d/windows.yml: Drop msys2-32bit job +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +MSYS2 is dropping support for 32-bit Windows. This shows up for us +as various packages we were using in our CI job no longer being +available to install, which causes the job to fail. In commit +8e31b744fdf we dropped the dependency on libusb and spice, but the +dtc package has also now been removed. + +For us as QEMU upstream, "32 bit x86 hosts for system emulation" have +already been deprecated as of QEMU 8.0, so we are ready to drop them +anyway. + +Drop the msys2-32bit CI job, as the first step in doing this. + +This is cc'd to stable, because this job will also be broken for CI +on the stable branches. We can't drop 32-bit support entirely there, +but we will still be covering at least compilation for 32-bit Windows +via the cross-win32-system job. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Peter Maydell +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Thomas Huth +Reviewed-by: Alex Bennée +Message-id: 20240220165602.135695-1-peter.maydell@linaro.org +(cherry picked from commit 5cd3ae4903e33982e7a9bbd04674af517e796d6e) +Signed-off-by: Michael Tokarev +--- + .gitlab-ci.d/windows.yml | 9 --------- + 1 file changed, 9 deletions(-) + +diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml +index 5c1e385..8fc0821 100644 +--- a/.gitlab-ci.d/windows.yml ++++ b/.gitlab-ci.d/windows.yml +@@ -131,12 +131,3 @@ msys2-64bit: + # qTests don't run successfully with "--without-default-devices", + # so let's exclude the qtests from CI for now. + TEST_ARGS: --no-suite qtest +- +-msys2-32bit: +- extends: .shared_msys2_builder +- variables: +- MINGW_TARGET: mingw-w64-i686 +- MSYSTEM: MINGW32 +- EXTRA_PACKAGES: +- CONFIGURE_ARGS: --target-list=ppc64-softmmu -Ddebug=false -Doptimization=0 +- TEST_ARGS: --no-suite qtest +-- +1.8.3.1 + diff --git a/0129-target-ppc-Fix-lxv-stxv-MSR-facility-check.patch b/0129-target-ppc-Fix-lxv-stxv-MSR-facility-check.patch new file mode 100644 index 0000000000000000000000000000000000000000..284822026149df004fab704e2a403bec44c1864b --- /dev/null +++ b/0129-target-ppc-Fix-lxv-stxv-MSR-facility-check.patch @@ -0,0 +1,49 @@ +From 175bdedfa96feb06c325489bf1594822b0d7e8df Mon Sep 17 00:00:00 2001 +From: Nicholas Piggin +Date: Tue, 13 Feb 2024 17:50:43 +1000 +Subject: [PATCH 137/293] target/ppc: Fix lxv/stxv MSR facility check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The move to decodetree flipped the inequality test for the VEC / VSX +MSR facility check. + +This caused application crashes under Linux, where these facility +unavailable interrupts are used for lazy-switching of VEC/VSX register +sets. Getting the incorrect interrupt would result in wrong registers +being loaded, potentially overwriting live values and/or exposing +stale ones. + +Cc: qemu-stable@nongnu.org +Reported-by: Joel Stanley +Fixes: 70426b5bb738 ("target/ppc: moved stxvx and lxvx from legacy to decodtree") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1769 +Reviewed-by: Harsh Prateek Bora +Tested-by: Harsh Prateek Bora +Reviewed-by: Cédric Le Goater +Tested-by: Cédric Le Goater +Signed-off-by: Nicholas Piggin + +(cherry picked from commit 2cc0e449d17310877fb28a942d4627ad22bb68ea) +Signed-off-by: Michael Tokarev +--- + target/ppc/translate/vsx-impl.c.inc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc +index 6db87ab..0266f09 100644 +--- a/target/ppc/translate/vsx-impl.c.inc ++++ b/target/ppc/translate/vsx-impl.c.inc +@@ -2268,7 +2268,7 @@ static bool do_lstxv(DisasContext *ctx, int ra, TCGv displ, + + static bool do_lstxv_D(DisasContext *ctx, arg_D *a, bool store, bool paired) + { +- if (paired || a->rt >= 32) { ++ if (paired || a->rt < 32) { + REQUIRE_VSX(ctx); + } else { + REQUIRE_VECTOR(ctx); +-- +1.8.3.1 + diff --git a/0130-target-ppc-Fix-crash-on-machine-check-caused-by-ifet.patch b/0130-target-ppc-Fix-crash-on-machine-check-caused-by-ifet.patch new file mode 100644 index 0000000000000000000000000000000000000000..2478d63eb5c884e1774dfb1a842cfcd28e092cf1 --- /dev/null +++ b/0130-target-ppc-Fix-crash-on-machine-check-caused-by-ifet.patch @@ -0,0 +1,122 @@ +From 131ed62955eed97874b14deda7256baf526a9178 Mon Sep 17 00:00:00 2001 +From: Nicholas Piggin +Date: Fri, 15 Dec 2023 18:58:49 +1000 +Subject: [PATCH 138/293] target/ppc: Fix crash on machine check caused by + ifetch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +is_prefix_insn_excp() loads the first word of the instruction address +which caused an exception, to determine whether or not it was prefixed +so the prefix bit can be set in [H]SRR1. + +This works if the instruction image can be loaded, but if the exception +was caused by an ifetch, this load could fail and cause a recursive +exception and crash. Machine checks caused by ifetch are not excluded +from the prefix check and can crash (see issue 2108 for an example). + +Fix this by excluding machine checks caused by ifetch from the prefix +check. + +Cc: qemu-stable@nongnu.org +Acked-by: Cédric Le Goater +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2108 +Fixes: 55a7fa34f89 ("target/ppc: Machine check on invalid real address access on POWER9/10") +Fixes: 5a5d3b23cb2 ("target/ppc: Add SRR1 prefix indication to interrupt handlers") +Signed-off-by: Nicholas Piggin +(cherry picked from commit c8fd9667e5975fe2e70a906e125a758737eab707) +Signed-off-by: Michael Tokarev +--- + target/ppc/excp_helper.c | 36 +++++++++++++++++++++++++----------- + 1 file changed, 25 insertions(+), 11 deletions(-) + +diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c +index a42743a..9b8fd69 100644 +--- a/target/ppc/excp_helper.c ++++ b/target/ppc/excp_helper.c +@@ -1312,6 +1312,10 @@ static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp) + { + CPUPPCState *env = &cpu->env; + ++ if (!(env->insns_flags2 & PPC2_ISA310)) { ++ return false; ++ } ++ + if (!tcg_enabled()) { + /* + * This does not load instructions and set the prefix bit correctly +@@ -1322,6 +1326,15 @@ static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp) + } + + switch (excp) { ++ case POWERPC_EXCP_MCHECK: ++ if (!(env->error_code & PPC_BIT(42))) { ++ /* ++ * Fetch attempt caused a machine check, so attempting to fetch ++ * again would cause a recursive machine check. ++ */ ++ return false; ++ } ++ break; + case POWERPC_EXCP_HDSI: + /* HDSI PRTABLE_FAULT has the originating access type in error_code */ + if ((env->spr[SPR_HDSISR] & DSISR_PRTABLE_FAULT) && +@@ -1332,10 +1345,10 @@ static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp) + * instruction at NIP would cause recursive faults with the same + * translation). + */ +- break; ++ return false; + } +- /* fall through */ +- case POWERPC_EXCP_MCHECK: ++ break; ++ + case POWERPC_EXCP_DSI: + case POWERPC_EXCP_DSEG: + case POWERPC_EXCP_ALIGN: +@@ -1346,17 +1359,13 @@ static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp) + case POWERPC_EXCP_VPU: + case POWERPC_EXCP_VSXU: + case POWERPC_EXCP_FU: +- case POWERPC_EXCP_HV_FU: { +- uint32_t insn = ppc_ldl_code(env, env->nip); +- if (is_prefix_insn(env, insn)) { +- return true; +- } ++ case POWERPC_EXCP_HV_FU: + break; +- } + default: +- break; ++ return false; + } +- return false; ++ ++ return is_prefix_insn(env, ppc_ldl_code(env, env->nip)); + } + #else + static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp) +@@ -3224,6 +3233,7 @@ void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + + switch (env->excp_model) { + #if defined(TARGET_PPC64) ++ case POWERPC_EXCP_POWER8: + case POWERPC_EXCP_POWER9: + case POWERPC_EXCP_POWER10: + /* +@@ -3245,6 +3255,10 @@ void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + env->error_code |= PPC_BIT(42); + + } else { /* Fetch */ ++ /* ++ * is_prefix_insn_excp() tests !PPC_BIT(42) to avoid fetching ++ * the instruction, so that must always be clear for fetches. ++ */ + env->error_code = PPC_BIT(36) | PPC_BIT(44) | PPC_BIT(45); + } + break; +-- +1.8.3.1 + diff --git a/0131-hw-nvme-fix-invalid-endian-conversion.patch b/0131-hw-nvme-fix-invalid-endian-conversion.patch new file mode 100644 index 0000000000000000000000000000000000000000..68f62c3573539632382ba6700b938c711e09d6a5 --- /dev/null +++ b/0131-hw-nvme-fix-invalid-endian-conversion.patch @@ -0,0 +1,41 @@ +From e4e36e65c9416c225cc684d82754ba1e5c3ca8ff Mon Sep 17 00:00:00 2001 +From: Klaus Jensen +Date: Thu, 22 Feb 2024 10:29:06 +0100 +Subject: [PATCH 141/293] hw/nvme: fix invalid endian conversion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +numcntl is one byte and so is max_vfs. Using cpu_to_le16 on big endian +hosts results in numcntl being set to 0. + +Fix by dropping the endian conversion. + +Fixes: 99f48ae7ae ("hw/nvme: Add support for Secondary Controller List") +Reported-by: Kevin Wolf +Signed-off-by: Klaus Jensen +Reviewed-by: Minwoo Im +Message-ID: <20240222-fix-sriov-numcntl-v1-1-d60bea5e72d0@samsung.com> +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit d2b5bb860e6c17442ad95cc275feb07c1665be5c) +Signed-off-by: Michael Tokarev +--- + hw/nvme/ctrl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index f026245..76fe039 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -7924,7 +7924,7 @@ static void nvme_init_state(NvmeCtrl *n) + n->aer_reqs = g_new0(NvmeRequest *, n->params.aerl + 1); + QTAILQ_INIT(&n->aer_queue); + +- list->numcntl = cpu_to_le16(max_vfs); ++ list->numcntl = max_vfs; + for (i = 0; i < max_vfs; i++) { + sctrl = &list->sec[i]; + sctrl->pcid = cpu_to_le16(n->cntlid); +-- +1.8.3.1 + diff --git a/0132-pl031-Update-last-RTCLR-value-on-write-in-case-it-s-.patch b/0132-pl031-Update-last-RTCLR-value-on-write-in-case-it-s-.patch new file mode 100644 index 0000000000000000000000000000000000000000..bf99e3430ae622c796cbe40cca5627b882e29f7b --- /dev/null +++ b/0132-pl031-Update-last-RTCLR-value-on-write-in-case-it-s-.patch @@ -0,0 +1,41 @@ +From a0fb839d0a48b1d421c41e301cadb6e5cd516eed Mon Sep 17 00:00:00 2001 +From: Jessica Clarke +Date: Mon, 26 Feb 2024 14:07:24 +0000 +Subject: [PATCH 142/293] pl031: Update last RTCLR value on write in case it's + read back +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The PL031 allows you to read RTCLR, which is meant to give you the last +value written. PL031State has an lr field which is used when reading +from RTCLR, and is present in the VM migration state, but we never +actually update it, so it always reads as its initial 0 value. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Jessica Clarke +Reviewed-by: Alex Bennée +Message-id: 20240222000341.1562443-1-jrtc27@jrtc27.com +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +(cherry picked from commit 4d28d57c9f2eb1cdf70b29cea6e50282e010075b) +Signed-off-by: Michael Tokarev +--- + hw/rtc/pl031.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/rtc/pl031.c b/hw/rtc/pl031.c +index b01d0e7..2f3cd04 100644 +--- a/hw/rtc/pl031.c ++++ b/hw/rtc/pl031.c +@@ -141,6 +141,7 @@ static void pl031_write(void * opaque, hwaddr offset, + g_autofree const char *qom_path = object_get_canonical_path(opaque); + struct tm tm; + ++ s->lr = value; + s->tick_offset += value - pl031_get_count(s); + + qemu_get_timedate(&tm, s->tick_offset); +-- +1.8.3.1 + diff --git a/0133-target-i386-mask-high-bits-of-CR3-in-32-bit-mode.patch b/0133-target-i386-mask-high-bits-of-CR3-in-32-bit-mode.patch new file mode 100644 index 0000000000000000000000000000000000000000..65d9b126162cf1e346d5c0a9a447c719ce5836a0 --- /dev/null +++ b/0133-target-i386-mask-high-bits-of-CR3-in-32-bit-mode.patch @@ -0,0 +1,45 @@ +From 6ed8211379b8bbd9d4d9f56a734819945a9711d6 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 22 Dec 2023 09:27:36 +0100 +Subject: [PATCH 143/293] target/i386: mask high bits of CR3 in 32-bit mode + +CR3 bits 63:32 are ignored in 32-bit mode (either legacy 2-level +paging or PAE paging). Do this in mmu_translate() to remove +the last where get_physical_address() meaningfully drops the high +bits of the address. + +Cc: qemu-stable@nongnu.org +Suggested-by: Richard Henderson +Fixes: 4a1e9d4d11c ("target/i386: Use atomic operations for pte updates", 2022-10-18) +Signed-off-by: Paolo Bonzini +(cherry picked from commit 68fb78d7d5723066ec2cacee7d25d67a4143b42f) +Signed-off-by: Michael Tokarev +--- + target/i386/tcg/sysemu/excp_helper.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c +index 5b86f43..11126c8 100644 +--- a/target/i386/tcg/sysemu/excp_helper.c ++++ b/target/i386/tcg/sysemu/excp_helper.c +@@ -238,7 +238,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + /* + * Page table level 3 + */ +- pte_addr = ((in->cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & a20_mask; ++ pte_addr = ((in->cr3 & 0xffffffe0ULL) + ((addr >> 27) & 0x18)) & a20_mask; + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } +@@ -306,7 +306,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + /* + * Page table level 2 + */ +- pte_addr = ((in->cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask; ++ pte_addr = ((in->cr3 & 0xfffff000ULL) + ((addr >> 20) & 0xffc)) & a20_mask; + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } +-- +1.8.3.1 + diff --git a/0134-target-i386-check-validity-of-VMCB-addresses.patch b/0134-target-i386-check-validity-of-VMCB-addresses.patch new file mode 100644 index 0000000000000000000000000000000000000000..2df3783146262a2edc9de7eaa557f9c4ed394eb6 --- /dev/null +++ b/0134-target-i386-check-validity-of-VMCB-addresses.patch @@ -0,0 +1,109 @@ +From 5c4091fe07a1a4447d1db749db34da3f7c599c0d Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 22 Dec 2023 17:47:38 +0100 +Subject: [PATCH 144/293] target/i386: check validity of VMCB addresses + +MSR_VM_HSAVE_PA bits 0-11 are reserved, as are the bits above the +maximum physical address width of the processor. Setting them to +1 causes a #GP (see "15.30.4 VM_HSAVE_PA MSR" in the AMD manual). + +The same is true of VMCB addresses passed to VMRUN/VMLOAD/VMSAVE, +even though the manual is not clear on that. + +Cc: qemu-stable@nongnu.org +Fixes: 4a1e9d4d11c ("target/i386: Use atomic operations for pte updates", 2022-10-18) +Signed-off-by: Paolo Bonzini +(cherry picked from commit d09c79010ffd880dc69e7a21e3cfdef90b928fb8) +Signed-off-by: Michael Tokarev +--- + target/i386/tcg/sysemu/misc_helper.c | 3 +++ + target/i386/tcg/sysemu/svm_helper.c | 27 +++++++++++++++++++++------ + 2 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c +index e1528b7..1901712 100644 +--- a/target/i386/tcg/sysemu/misc_helper.c ++++ b/target/i386/tcg/sysemu/misc_helper.c +@@ -201,6 +201,9 @@ void helper_wrmsr(CPUX86State *env) + tlb_flush(cs); + break; + case MSR_VM_HSAVE_PA: ++ if (val & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) { ++ goto error; ++ } + env->vm_hsave = val; + break; + #ifdef TARGET_X86_64 +diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c +index 32ff0db..5d6de22 100644 +--- a/target/i386/tcg/sysemu/svm_helper.c ++++ b/target/i386/tcg/sysemu/svm_helper.c +@@ -164,14 +164,19 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) + uint64_t new_cr3; + uint64_t new_cr4; + +- cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC()); +- + if (aflag == 2) { + addr = env->regs[R_EAX]; + } else { + addr = (uint32_t)env->regs[R_EAX]; + } + ++ /* Exceptions are checked before the intercept. */ ++ if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) { ++ raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); ++ } ++ ++ cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC()); ++ + qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr); + + env->vm_vmcb = addr; +@@ -463,14 +468,19 @@ void helper_vmload(CPUX86State *env, int aflag) + int mmu_idx = MMU_PHYS_IDX; + target_ulong addr; + +- cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC()); +- + if (aflag == 2) { + addr = env->regs[R_EAX]; + } else { + addr = (uint32_t)env->regs[R_EAX]; + } + ++ /* Exceptions are checked before the intercept. */ ++ if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) { ++ raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); ++ } ++ ++ cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC()); ++ + if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) { + mmu_idx = MMU_NESTED_IDX; + } +@@ -519,14 +529,19 @@ void helper_vmsave(CPUX86State *env, int aflag) + int mmu_idx = MMU_PHYS_IDX; + target_ulong addr; + +- cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); +- + if (aflag == 2) { + addr = env->regs[R_EAX]; + } else { + addr = (uint32_t)env->regs[R_EAX]; + } + ++ /* Exceptions are checked before the intercept. */ ++ if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) { ++ raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); ++ } ++ ++ cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); ++ + if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) { + mmu_idx = MMU_NESTED_IDX; + } +-- +1.8.3.1 + diff --git a/0135-target-i386-Fix-physical-address-truncation.patch b/0135-target-i386-Fix-physical-address-truncation.patch new file mode 100644 index 0000000000000000000000000000000000000000..8e788c73c1ea8d3951f6676905c9232387b506f2 --- /dev/null +++ b/0135-target-i386-Fix-physical-address-truncation.patch @@ -0,0 +1,99 @@ +From a28b6b4e7431a7557958a8b105626a5a5958791c Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 22 Dec 2023 18:01:52 +0100 +Subject: [PATCH 145/293] target/i386: Fix physical address truncation + +The address translation logic in get_physical_address() will currently +truncate physical addresses to 32 bits unless long mode is enabled. +This is incorrect when using physical address extensions (PAE) outside +of long mode, with the result that a 32-bit operating system using PAE +to access memory above 4G will experience undefined behaviour. + +The truncation code was originally introduced in commit 33dfdb5 ("x86: +only allow real mode to access 32bit without LMA"), where it applied +only to translations performed while paging is disabled (and so cannot +affect guests using PAE). + +Commit 9828198 ("target/i386: Add MMU_PHYS_IDX and MMU_NESTED_IDX") +rearranged the code such that the truncation also applied to the use +of MMU_PHYS_IDX and MMU_NESTED_IDX. Commit 4a1e9d4 ("target/i386: Use +atomic operations for pte updates") brought this truncation into scope +for page table entry accesses, and is the first commit for which a +Windows 10 32-bit guest will reliably fail to boot if memory above 4G +is present. + +The truncation code however is not completely redundant. Even though the +maximum address size for any executed instruction is 32 bits, helpers for +operations such as BOUND, FSAVE or XSAVE may ask get_physical_address() +to translate an address outside of the 32-bit range, if invoked with an +argument that is close to the 4G boundary. Likewise for processor +accesses, for example TSS or IDT accesses, when EFER.LMA==0. + +So, move the address truncation in get_physical_address() so that it +applies to 32-bit MMU indexes, but not to MMU_PHYS_IDX and MMU_NESTED_IDX. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2040 +Fixes: 4a1e9d4d11c ("target/i386: Use atomic operations for pte updates", 2022-10-18) +Cc: qemu-stable@nongnu.org +Co-developed-by: Michael Brown +Signed-off-by: Michael Brown +Signed-off-by: Paolo Bonzini +(cherry picked from commit b1661801c184119a10ad6cbc3b80330fc22e7b2c) +Signed-off-by: Michael Tokarev +(Mjt: drop unrelated change in target/i386/cpu.c) +--- + target/i386/cpu.h | 6 ++++++ + target/i386/tcg/sysemu/excp_helper.c | 12 +++++------- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index ef987f3..705d925 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -2302,6 +2302,12 @@ static inline int cpu_mmu_index(CPUX86State *env, bool ifetch) + ? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX; + } + ++static inline bool is_mmu_index_32(int mmu_index) ++{ ++ assert(mmu_index < MMU_PHYS_IDX); ++ return mmu_index & 1; ++} ++ + static inline int cpu_mmu_index_kernel(CPUX86State *env) + { + return !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP_IDX : +diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c +index 11126c8..38c313a 100644 +--- a/target/i386/tcg/sysemu/excp_helper.c ++++ b/target/i386/tcg/sysemu/excp_helper.c +@@ -557,6 +557,10 @@ static bool get_physical_address(CPUX86State *env, vaddr addr, + break; + + default: ++ if (is_mmu_index_32(mmu_idx)) { ++ addr = (uint32_t)addr; ++ } ++ + if (likely(env->cr[0] & CR0_PG_MASK)) { + in.cr3 = env->cr[3]; + in.mmu_idx = mmu_idx; +@@ -580,14 +584,8 @@ static bool get_physical_address(CPUX86State *env, vaddr addr, + break; + } + +- /* Translation disabled. */ ++ /* No translation needed. */ + out->paddr = addr & x86_get_a20_mask(env); +-#ifdef TARGET_X86_64 +- if (!(env->hflags & HF_LMA_MASK)) { +- /* Without long mode we can only address 32bits in real mode */ +- out->paddr = (uint32_t)out->paddr; +- } +-#endif + out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + out->page_size = TARGET_PAGE_SIZE; + return true; +-- +1.8.3.1 + diff --git a/0136-target-i386-remove-unnecessary-wrong-application-of-.patch b/0136-target-i386-remove-unnecessary-wrong-application-of-.patch new file mode 100644 index 0000000000000000000000000000000000000000..82e8076da0203af1a87d119bc2ade0fa62ba4fe0 --- /dev/null +++ b/0136-target-i386-remove-unnecessary-wrong-application-of-.patch @@ -0,0 +1,113 @@ +From 6801a20ebd0e541f45855665a75571d4d24188a0 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 22 Dec 2023 09:52:27 +0100 +Subject: [PATCH 146/293] target/i386: remove unnecessary/wrong application of + the A20 mask + +If ptw_translate() does a MMU_PHYS_IDX access, the A20 mask is already +applied in get_physical_address(), which is called via probe_access_full() +and x86_cpu_tlb_fill(). + +If ptw_translate() on the other hand does a MMU_NESTED_IDX access, +the A20 mask must not be applied to the address that is looked up in +the nested page tables; it must be applied only to the addresses that +hold the NPT entries (which is achieved via MMU_PHYS_IDX, per the +previous paragraph). + +Therefore, we can remove A20 masking from the computation of the page +table entry's address, and let get_physical_address() or mmu_translate() +apply it when they know they are returning a host-physical address. + +Cc: qemu-stable@nongnu.org +Fixes: 4a1e9d4d11c ("target/i386: Use atomic operations for pte updates", 2022-10-18) +Signed-off-by: Paolo Bonzini +(cherry picked from commit a28fe7dc1939333c81b895cdced81c69eb7c5ad0) +Signed-off-by: Michael Tokarev +--- + target/i386/tcg/sysemu/excp_helper.c | 21 ++++++++------------- + 1 file changed, 8 insertions(+), 13 deletions(-) + +diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c +index 38c313a..89df61e 100644 +--- a/target/i386/tcg/sysemu/excp_helper.c ++++ b/target/i386/tcg/sysemu/excp_helper.c +@@ -164,8 +164,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + /* + * Page table level 5 + */ +- pte_addr = ((in->cr3 & ~0xfff) + +- (((addr >> 48) & 0x1ff) << 3)) & a20_mask; ++ pte_addr = (in->cr3 & ~0xfff) + (((addr >> 48) & 0x1ff) << 3); + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } +@@ -189,8 +188,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + /* + * Page table level 4 + */ +- pte_addr = ((pte & PG_ADDRESS_MASK) + +- (((addr >> 39) & 0x1ff) << 3)) & a20_mask; ++ pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 39) & 0x1ff) << 3); + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } +@@ -210,8 +208,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + /* + * Page table level 3 + */ +- pte_addr = ((pte & PG_ADDRESS_MASK) + +- (((addr >> 30) & 0x1ff) << 3)) & a20_mask; ++ pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3); + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } +@@ -238,7 +235,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + /* + * Page table level 3 + */ +- pte_addr = ((in->cr3 & 0xffffffe0ULL) + ((addr >> 27) & 0x18)) & a20_mask; ++ pte_addr = (in->cr3 & 0xffffffe0ULL) + ((addr >> 27) & 0x18); + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } +@@ -260,8 +257,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + /* + * Page table level 2 + */ +- pte_addr = ((pte & PG_ADDRESS_MASK) + +- (((addr >> 21) & 0x1ff) << 3)) & a20_mask; ++ pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3); + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } +@@ -287,8 +283,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + /* + * Page table level 1 + */ +- pte_addr = ((pte & PG_ADDRESS_MASK) + +- (((addr >> 12) & 0x1ff) << 3)) & a20_mask; ++ pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3); + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } +@@ -306,7 +301,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + /* + * Page table level 2 + */ +- pte_addr = ((in->cr3 & 0xfffff000ULL) + ((addr >> 20) & 0xffc)) & a20_mask; ++ pte_addr = (in->cr3 & 0xfffff000ULL) + ((addr >> 20) & 0xffc); + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } +@@ -335,7 +330,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + /* + * Page table level 1 + */ +- pte_addr = ((pte & ~0xfffu) + ((addr >> 10) & 0xffc)) & a20_mask; ++ pte_addr = (pte & ~0xfffu) + ((addr >> 10) & 0xffc); + if (!ptw_translate(&pte_trans, pte_addr)) { + return false; + } +-- +1.8.3.1 + diff --git a/0137-target-i386-leave-the-A20-bit-set-in-the-final-NPT-w.patch b/0137-target-i386-leave-the-A20-bit-set-in-the-final-NPT-w.patch new file mode 100644 index 0000000000000000000000000000000000000000..3045ce14b7e4ad2f43858da7055609192845ba9f --- /dev/null +++ b/0137-target-i386-leave-the-A20-bit-set-in-the-final-NPT-w.patch @@ -0,0 +1,62 @@ +From decafac46bec616add565fcfa71ce0184850f79b Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 22 Dec 2023 09:48:35 +0100 +Subject: [PATCH 147/293] target/i386: leave the A20 bit set in the final NPT + walk + +The A20 mask is only applied to the final memory access. Nested +page tables are always walked with the raw guest-physical address. + +Unlike the previous patch, in this one the masking must be kept, but +it was done too early. + +Cc: qemu-stable@nongnu.org +Fixes: 4a1e9d4d11c ("target/i386: Use atomic operations for pte updates", 2022-10-18) +Signed-off-by: Paolo Bonzini +(cherry picked from commit b5a9de3259f4c791bde2faff086dd5737625e41e) +Signed-off-by: Michael Tokarev +--- + target/i386/tcg/sysemu/excp_helper.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c +index 89df61e..e16d3a6 100644 +--- a/target/i386/tcg/sysemu/excp_helper.c ++++ b/target/i386/tcg/sysemu/excp_helper.c +@@ -134,7 +134,6 @@ static inline bool ptw_setl(const PTETranslate *in, uint32_t old, uint32_t set) + static bool mmu_translate(CPUX86State *env, const TranslateParams *in, + TranslateResult *out, TranslateFault *err) + { +- const int32_t a20_mask = x86_get_a20_mask(env); + const target_ulong addr = in->addr; + const int pg_mode = in->pg_mode; + const bool is_user = (in->mmu_idx == MMU_USER_IDX); +@@ -417,10 +416,13 @@ do_check_protect_pse36: + } + } + +- /* align to page_size */ +- paddr = (pte & a20_mask & PG_ADDRESS_MASK & ~(page_size - 1)) +- | (addr & (page_size - 1)); ++ /* merge offset within page */ ++ paddr = (pte & PG_ADDRESS_MASK & ~(page_size - 1)) | (addr & (page_size - 1)); + ++ /* ++ * Note that NPT is walked (for both paging structures and final guest ++ * addresses) using the address with the A20 bit set. ++ */ + if (in->ptw_idx == MMU_NESTED_IDX) { + CPUTLBEntryFull *full; + int flags, nested_page_size; +@@ -459,7 +461,7 @@ do_check_protect_pse36: + } + } + +- out->paddr = paddr; ++ out->paddr = paddr & x86_get_a20_mask(env); + out->prot = prot; + out->page_size = page_size; + return true; +-- +1.8.3.1 + diff --git a/0138-tests-vm-update-openbsd-image-to-7.4.patch b/0138-tests-vm-update-openbsd-image-to-7.4.patch new file mode 100644 index 0000000000000000000000000000000000000000..782d82088756b09374137035492270e03f1adfe5 --- /dev/null +++ b/0138-tests-vm-update-openbsd-image-to-7.4.patch @@ -0,0 +1,62 @@ +From 36d50b4bde643e02fe42779794a4e3c5a9488649 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Tue, 27 Feb 2024 14:43:10 +0000 +Subject: [PATCH 148/293] tests/vm: update openbsd image to 7.4 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The old links are dead so even if we have the ISO cached we can't +finish the install. Update to the current stable and tweak the install +strings. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2192 +Tested-by: Thomas Huth +Reviewed-by: Thomas Huth +Signed-off-by: Alex Bennée +Message-Id: <20240227144335.1196131-5-alex.bennee@linaro.org> +(cherry picked from commit 8467ac75b3b7207a49a1c6c7b87f0f7d2d0cea18) +Signed-off-by: Michael Tokarev +--- + tests/vm/openbsd | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/tests/vm/openbsd b/tests/vm/openbsd +index 85c5bb3..85c9863 100755 +--- a/tests/vm/openbsd ++++ b/tests/vm/openbsd +@@ -22,8 +22,8 @@ class OpenBSDVM(basevm.BaseVM): + name = "openbsd" + arch = "x86_64" + +- link = "https://cdn.openbsd.org/pub/OpenBSD/7.2/amd64/install72.iso" +- csum = "0369ef40a3329efcb978c578c7fdc7bda71e502aecec930a74b44160928c91d3" ++ link = "https://cdn.openbsd.org/pub/OpenBSD/7.4/amd64/install74.iso" ++ csum = "a1001736ed9fe2307965b5fcdb426ae11f9b80d26eb21e404a705144a0a224a0" + size = "20G" + pkgs = [ + # tools +@@ -99,10 +99,10 @@ class OpenBSDVM(basevm.BaseVM): + self.console_wait_send("(I)nstall", "i\n") + self.console_wait_send("Terminal type", "xterm\n") + self.console_wait_send("System hostname", "openbsd\n") +- self.console_wait_send("Which network interface", "vio0\n") ++ self.console_wait_send("Network interface to configure", "vio0\n") + self.console_wait_send("IPv4 address", "autoconf\n") + self.console_wait_send("IPv6 address", "none\n") +- self.console_wait_send("Which network interface", "done\n") ++ self.console_wait_send("Network interface to configure", "done\n") + self.console_wait("Password for root account") + self.console_send("%s\n" % self._config["root_pass"]) + self.console_wait("Password for root account") +@@ -124,6 +124,7 @@ class OpenBSDVM(basevm.BaseVM): + self.console_wait_send("Allow root ssh login", "yes\n") + self.console_wait_send("timezone", "UTC\n") + self.console_wait_send("root disk", "\n") ++ self.console_wait_send("Encrypt the root disk with a passphrase", "no\n") + self.console_wait_send("(W)hole disk", "\n") + self.console_wait_send("(A)uto layout", "c\n") + +-- +1.8.3.1 + diff --git a/0139-tests-vm-avoid-re-building-the-VM-images-all-the-tim.patch b/0139-tests-vm-avoid-re-building-the-VM-images-all-the-tim.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e1a81038546dc7b15cbe3e072af808bb1199768 --- /dev/null +++ b/0139-tests-vm-avoid-re-building-the-VM-images-all-the-tim.patch @@ -0,0 +1,63 @@ +From 6c14f9318257107f911f133aafbaf4c5f888ec61 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Tue, 27 Feb 2024 14:43:09 +0000 +Subject: [PATCH 149/293] tests/vm: avoid re-building the VM images all the + time +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The main problem is that "check-venv" is a .PHONY target will always +evaluate and trigger a full re-build of the VM images. While its +tempting to drop it from the dependencies that does introduce a +breakage on freshly configured builds. + +Fortunately we do have the otherwise redundant --force flag for the +script which up until now was always on. If we make the usage of +--force conditional on dependencies other than check-venv triggering +the update we can avoid the costly rebuild and still run cleanly on a +fresh checkout. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2118 +Reviewed-by: Thomas Huth +Signed-off-by: Alex Bennée +Message-Id: <20240227144335.1196131-4-alex.bennee@linaro.org> +(cherry picked from commit 151b7dba391fab64cc008a1fdba6ddcf6f8c39c8) +Signed-off-by: Michael Tokarev +--- + tests/vm/Makefile.include | 2 +- + tests/vm/basevm.py | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include +index bf12e0f..ac56824 100644 +--- a/tests/vm/Makefile.include ++++ b/tests/vm/Makefile.include +@@ -102,7 +102,7 @@ $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \ + $(if $(LOG_CONSOLE),--log-console) \ + --source-path $(SRC_PATH) \ + --image "$@" \ +- --force \ ++ $(if $(filter-out check-venv, $?), --force) \ + --build-image $@, \ + " VM-IMAGE $*") + +diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py +index 61725b8..e38159a 100644 +--- a/tests/vm/basevm.py ++++ b/tests/vm/basevm.py +@@ -644,9 +644,9 @@ def main(vmcls, config=None): + vm = vmcls(args, config=config) + if args.build_image: + if os.path.exists(args.image) and not args.force: +- sys.stderr.writelines(["Image file exists: %s\n" % args.image, ++ sys.stderr.writelines(["Image file exists, skipping build: %s\n" % args.image, + "Use --force option to overwrite\n"]) +- return 1 ++ return 0 + return vm.build_image(args.image) + if args.build_qemu: + vm.add_source_dir(args.build_qemu) +-- +1.8.3.1 + diff --git a/0140-gitlab-force-allow-use-of-pip-in-Cirrus-jobs.patch b/0140-gitlab-force-allow-use-of-pip-in-Cirrus-jobs.patch new file mode 100644 index 0000000000000000000000000000000000000000..64925cb309dcd5ca8cf7a0462e3bc1e29b0c7201 --- /dev/null +++ b/0140-gitlab-force-allow-use-of-pip-in-Cirrus-jobs.patch @@ -0,0 +1,44 @@ +From 0e33e4e78e6b63cb9db158b0b8fc871fd2fc2c16 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Thu, 22 Feb 2024 11:40:38 +0000 +Subject: [PATCH 150/293] gitlab: force allow use of pip in Cirrus jobs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Python is transitioning to a world where you're not allowed to use 'pip +install' outside of a virutal env by default. The rationale is to stop +use of pip clashing with distro provided python packages, which creates +a major headache on distro upgrades. + +All our CI environments, however, are 100% disposable so the upgrade +headaches don't exist. Thus we can undo the python defaults to allow +pip to work. + +Signed-off-by: Daniel P. Berrangé +Tested-by: Philippe Mathieu-Daudé +Tested-by: Thomas Huth +Message-id: 20240222114038.2348718-1-berrange@redhat.com +Signed-off-by: Peter Maydell +(cherry picked from commit a8bf9de2f4f398315ac5340e4b88c478d5457731) +Signed-off-by: Michael Tokarev +--- + .gitlab-ci.d/cirrus/build.yml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/.gitlab-ci.d/cirrus/build.yml b/.gitlab-ci.d/cirrus/build.yml +index 29d55c4..43dd52d 100644 +--- a/.gitlab-ci.d/cirrus/build.yml ++++ b/.gitlab-ci.d/cirrus/build.yml +@@ -21,7 +21,7 @@ build_task: + install_script: + - @UPDATE_COMMAND@ + - @INSTALL_COMMAND@ @PKGS@ +- - if test -n "@PYPI_PKGS@" ; then @PIP3@ install @PYPI_PKGS@ ; fi ++ - if test -n "@PYPI_PKGS@" ; then PYLIB=$(@PYTHON@ -c 'import sysconfig; print(sysconfig.get_path("stdlib"))'); rm -f $PYLIB/EXTERNALLY-MANAGED; @PIP3@ install @PYPI_PKGS@ ; fi + clone_script: + - git clone --depth 100 "$CI_REPOSITORY_URL" . + - git fetch origin "$CI_COMMIT_REF_NAME" +-- +1.8.3.1 + diff --git a/0141-hw-intc-Kconfig-Fix-GIC-settings-when-using-without-.patch b/0141-hw-intc-Kconfig-Fix-GIC-settings-when-using-without-.patch new file mode 100644 index 0000000000000000000000000000000000000000..b8eb36aa5c6719368ed7e1d31f52d7c19e6c7a02 --- /dev/null +++ b/0141-hw-intc-Kconfig-Fix-GIC-settings-when-using-without-.patch @@ -0,0 +1,60 @@ +From 829bb27765afba34a54c49c47b5c658ac84bec3a Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Wed, 21 Feb 2024 12:00:59 +0100 +Subject: [PATCH 151/293] hw/intc/Kconfig: Fix GIC settings when using + "--without-default-devices" + +When using "--without-default-devices", the ARM_GICV3_TCG and ARM_GIC_KVM +settings currently get disabled, though the arm virt machine is only of +very limited use in that case. This also causes the migration-test to +fail in such builds. Let's make sure that we always keep the GIC switches +enabled in the --without-default-devices builds, too. + +Message-ID: <20240221110059.152665-1-thuth@redhat.com> +Tested-by: Fabiano Rosas +Signed-off-by: Thomas Huth +(cherry picked from commit 8bd3f84d1f6fba0edebc450be6fa2c7630584df9) +Signed-off-by: Michael Tokarev +--- + hw/intc/Kconfig | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig +index 97d550b..2b5b2d2 100644 +--- a/hw/intc/Kconfig ++++ b/hw/intc/Kconfig +@@ -12,10 +12,6 @@ config IOAPIC + bool + select I8259 + +-config ARM_GIC +- bool +- select MSI_NONBROKEN +- + config OPENPIC + bool + select MSI_NONBROKEN +@@ -25,14 +21,18 @@ config APIC + select MSI_NONBROKEN + select I8259 + ++config ARM_GIC ++ bool ++ select ARM_GICV3_TCG if TCG ++ select ARM_GIC_KVM if KVM ++ select MSI_NONBROKEN ++ + config ARM_GICV3_TCG + bool +- default y + depends on ARM_GIC && TCG + + config ARM_GIC_KVM + bool +- default y + depends on ARM_GIC && KVM + + config XICS +-- +1.8.3.1 + diff --git a/0142-hw-usb-bus.c-PCAP-adding-0xA-in-Windows-version.patch b/0142-hw-usb-bus.c-PCAP-adding-0xA-in-Windows-version.patch new file mode 100644 index 0000000000000000000000000000000000000000..19ebf53a4001959f41abf3be000495e38f7f2afc --- /dev/null +++ b/0142-hw-usb-bus.c-PCAP-adding-0xA-in-Windows-version.patch @@ -0,0 +1,63 @@ +From e6ce551c75827bc8907a3898a2f5f8132ba83db4 Mon Sep 17 00:00:00 2001 +From: Benjamin David Lunt +Date: Sun, 25 Feb 2024 12:49:51 -0700 +Subject: [PATCH 152/293] hw/usb/bus.c: PCAP adding 0xA in Windows version + +Since Windows text files use CRLFs for all \n, the Windows version of QEMU +inserts a CR in the PCAP stream when a LF is encountered when using USB PCAP +files. This is due to the fact that the PCAP file is opened as TEXT instead +of BINARY. + +To show an example, when using a very common protocol to USB disks, the BBB +protocol uses a 10-byte command packet. For example, the READ_CAPACITY(10) +command will have a command block length of 10 (0xA). When this 10-byte +command (part of the 31-byte CBW) is placed into the PCAP file, the Windows +file manager inserts a 0xD before the 0xA, turning the 31-byte CBW into a +32-byte CBW. + +Actual CBW: + 0040 55 53 42 43 01 00 00 00 08 00 00 00 80 00 0a 25 USBC...........% + 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............... + +PCAP CBW + 0040 55 53 42 43 01 00 00 00 08 00 00 00 80 00 0d 0a USBC............ + 0050 25 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 %.............. + +I believe simply opening the PCAP file as BINARY instead of TEXT will fix +this issue. + +Resolves: https://bugs.launchpad.net/qemu/+bug/2054889 +Signed-off-by: Benjamin David Lunt +Message-ID: <000101da6823$ce1bbf80$6a533e80$@fysnet.net> +[thuth: Break long line to avoid checkpatch.pl error] +Signed-off-by: Thomas Huth +(cherry picked from commit 5e02a4fdebc442e34c5bb05e4540f85cc6e802f0) +Signed-off-by: Michael Tokarev +--- + hw/usb/bus.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/bus.c b/hw/usb/bus.c +index 92d6ed5..4d4c671 100644 +--- a/hw/usb/bus.c ++++ b/hw/usb/bus.c +@@ -273,13 +273,14 @@ static void usb_qdev_realize(DeviceState *qdev, Error **errp) + } + + if (dev->pcap_filename) { +- int fd = qemu_open_old(dev->pcap_filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); ++ int fd = qemu_open_old(dev->pcap_filename, ++ O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666); + if (fd < 0) { + error_setg(errp, "open %s failed", dev->pcap_filename); + usb_qdev_unrealize(qdev); + return; + } +- dev->pcap = fdopen(fd, "w"); ++ dev->pcap = fdopen(fd, "wb"); + usb_pcap_init(dev->pcap); + } + } +-- +1.8.3.1 + diff --git a/0143-tests-unit-test-util-sockets-Remove-temporary-file-a.patch b/0143-tests-unit-test-util-sockets-Remove-temporary-file-a.patch new file mode 100644 index 0000000000000000000000000000000000000000..30821670e5a86aa6b4784cd714feb7e8f15694e6 --- /dev/null +++ b/0143-tests-unit-test-util-sockets-Remove-temporary-file-a.patch @@ -0,0 +1,39 @@ +From 2a97c05796a42dc0d0104fef76a1ac87153c2462 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Mon, 26 Feb 2024 09:27:28 +0100 +Subject: [PATCH 153/293] tests/unit/test-util-sockets: Remove temporary file + after test +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +test-util-sockets leaves the temporary socket files around in the +temporary files folder. Let's better remove them at the end of the +testing. + +Fixes: 4d3a329af5 ("tests/util-sockets: add abstract unix socket cases") +Message-ID: <20240226082728.249753-1-thuth@redhat.com> +Reviewed-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Thomas Huth +(cherry picked from commit f0cb6828ae34fb56fbb869bb3147a636d1c984ce) +Signed-off-by: Michael Tokarev +--- + tests/unit/test-util-sockets.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c +index 63909cc..4c9dd0b 100644 +--- a/tests/unit/test-util-sockets.c ++++ b/tests/unit/test-util-sockets.c +@@ -326,6 +326,7 @@ static void test_socket_unix_abstract(void) + test_socket_unix_abstract_row(&matrix[i]); + } + ++ unlink(addr.u.q_unix.path); + g_free(addr.u.q_unix.path); + } + +-- +1.8.3.1 + diff --git a/0144-chardev-char-socket-Fix-TLS-io-channels-sending-too-.patch b/0144-chardev-char-socket-Fix-TLS-io-channels-sending-too-.patch new file mode 100644 index 0000000000000000000000000000000000000000..ced342382be9fee8ffbf24b7c31ee923ff3b9904 --- /dev/null +++ b/0144-chardev-char-socket-Fix-TLS-io-channels-sending-too-.patch @@ -0,0 +1,90 @@ +From 21214699c23b8e1fd36c2a9965f9bcdc0008f101 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Thu, 29 Feb 2024 11:43:37 +0100 +Subject: [PATCH 154/293] chardev/char-socket: Fix TLS io channels sending too + much data to the backend +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit ffda5db65a ("io/channel-tls: fix handling of bigger read buffers") +changed the behavior of the TLS io channels to schedule a second reading +attempt if there is still incoming data pending. This caused a regression +with backends like the sclpconsole that check in their read function that +the sender does not try to write more bytes to it than the device can +currently handle. + +The problem can be reproduced like this: + + 1) In one terminal, do this: + + mkdir qemu-pki + cd qemu-pki + openssl genrsa 2048 > ca-key.pem + openssl req -new -x509 -nodes -days 365000 -key ca-key.pem -out ca-cert.pem + # enter some dummy value for the cert + openssl genrsa 2048 > server-key.pem + openssl req -new -x509 -nodes -days 365000 -key server-key.pem \ + -out server-cert.pem + # enter some other dummy values for the cert + + gnutls-serv --echo --x509cafile ca-cert.pem --x509keyfile server-key.pem \ + --x509certfile server-cert.pem -p 8338 + + 2) In another terminal, do this: + + wget https://download.fedoraproject.org/pub/fedora-secondary/releases/39/Cloud/s390x/images/Fedora-Cloud-Base-39-1.5.s390x.qcow2 + + qemu-system-s390x -nographic -nodefaults \ + -hda Fedora-Cloud-Base-39-1.5.s390x.qcow2 \ + -object tls-creds-x509,id=tls0,endpoint=client,verify-peer=false,dir=$PWD/qemu-pki \ + -chardev socket,id=tls_chardev,host=localhost,port=8338,tls-creds=tls0 \ + -device sclpconsole,chardev=tls_chardev,id=tls_serial + +QEMU then aborts after a second or two with: + + qemu-system-s390x: ../hw/char/sclpconsole.c:73: chr_read: Assertion + `size <= SIZE_BUFFER_VT220 - scon->iov_data_len' failed. + Aborted (core dumped) + +It looks like the second read does not trigger the chr_can_read() function +to be called before the second read, which should normally always be done +before sending bytes to a character device to see how much it can handle, +so the s->max_size in tcp_chr_read() still contains the old value from the +previous read. Let's make sure that we use the up-to-date value by calling +tcp_chr_read_poll() again here. + +Fixes: ffda5db65a ("io/channel-tls: fix handling of bigger read buffers") +Buglink: https://issues.redhat.com/browse/RHEL-24614 +Reviewed-by: "Daniel P. Berrangé" +Message-ID: <20240229104339.42574-1-thuth@redhat.com> +Reviewed-by: Antoine Damhet +Tested-by: Antoine Damhet +Reviewed-by: Marc-André Lureau +Signed-off-by: Thomas Huth +(cherry picked from commit 462945cd22d2bcd233401ed3aa167d83a8e35b05) +Signed-off-by: Michael Tokarev +--- + chardev/char-socket.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/chardev/char-socket.c b/chardev/char-socket.c +index 73947da..0348405 100644 +--- a/chardev/char-socket.c ++++ b/chardev/char-socket.c +@@ -492,9 +492,9 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) + s->max_size <= 0) { + return TRUE; + } +- len = sizeof(buf); +- if (len > s->max_size) { +- len = s->max_size; ++ len = tcp_chr_read_poll(opaque); ++ if (len > sizeof(buf)) { ++ len = sizeof(buf); + } + size = tcp_chr_recv(chr, (void *)buf, len); + if (size == 0 || (size == -1 && errno != EAGAIN)) { +-- +1.8.3.1 + diff --git a/0145-Update-version-for-8.2.2-release.patch b/0145-Update-version-for-8.2.2-release.patch new file mode 100644 index 0000000000000000000000000000000000000000..2bde96a8958c2f49d929cfcbc30811881296cb34 --- /dev/null +++ b/0145-Update-version-for-8.2.2-release.patch @@ -0,0 +1,20 @@ +From 11aa0b1ff115b86160c4d37e7c37e6a6b13b77ea Mon Sep 17 00:00:00 2001 +From: Michael Tokarev +Date: Mon, 4 Mar 2024 15:15:46 +0300 +Subject: [PATCH 155/293] Update version for 8.2.2 release + +Signed-off-by: Michael Tokarev +--- + VERSION | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/VERSION b/VERSION +index 2b0aa21..308c0cb 100644 +--- a/VERSION ++++ b/VERSION +@@ -1 +1 @@ +-8.2.1 ++8.2.2 +-- +1.8.3.1 + diff --git a/0146-target-i386-Add-new-CPU-model-SierraForest.patch b/0146-target-i386-Add-new-CPU-model-SierraForest.patch new file mode 100644 index 0000000000000000000000000000000000000000..28e1b8e41327bc2203d2c5aa9798689739f2c63a --- /dev/null +++ b/0146-target-i386-Add-new-CPU-model-SierraForest.patch @@ -0,0 +1,212 @@ +From acc384dec0fbaa0f6cd3532bd641a118bce98886 Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Wed, 20 Mar 2024 10:10:44 +0800 +Subject: [PATCH 156/293] target/i386: Add new CPU model SierraForest +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 6e82d3b6220777667968a04c87e1667f164ebe88 upstream. + +According to table 1-2 in Intel Architecture Instruction Set Extensions and +Future Features (rev 051) [1], SierraForest has the following new features +which have already been virtualized: + +- CMPCCXADD CPUID.(EAX=7,ECX=1):EAX[bit 7] +- AVX-IFMA CPUID.(EAX=7,ECX=1):EAX[bit 23] +- AVX-VNNI-INT8 CPUID.(EAX=7,ECX=1):EDX[bit 4] +- AVX-NE-CONVERT CPUID.(EAX=7,ECX=1):EDX[bit 5] + +Add above features to new CPU model SierraForest. Comparing with GraniteRapids +CPU model, SierraForest bare-metal removes the following features: + +- HLE CPUID.(EAX=7,ECX=0):EBX[bit 4] +- RTM CPUID.(EAX=7,ECX=0):EBX[bit 11] +- AVX512F CPUID.(EAX=7,ECX=0):EBX[bit 16] +- AVX512DQ CPUID.(EAX=7,ECX=0):EBX[bit 17] +- AVX512_IFMA CPUID.(EAX=7,ECX=0):EBX[bit 21] +- AVX512CD CPUID.(EAX=7,ECX=0):EBX[bit 28] +- AVX512BW CPUID.(EAX=7,ECX=0):EBX[bit 30] +- AVX512VL CPUID.(EAX=7,ECX=0):EBX[bit 31] +- AVX512_VBMI CPUID.(EAX=7,ECX=0):ECX[bit 1] +- AVX512_VBMI2 CPUID.(EAX=7,ECX=0):ECX[bit 6] +- AVX512_VNNI CPUID.(EAX=7,ECX=0):ECX[bit 11] +- AVX512_BITALG CPUID.(EAX=7,ECX=0):ECX[bit 12] +- AVX512_VPOPCNTDQ CPUID.(EAX=7,ECX=0):ECX[bit 14] +- LA57 CPUID.(EAX=7,ECX=0):ECX[bit 16] +- TSXLDTRK CPUID.(EAX=7,ECX=0):EDX[bit 16] +- AMX-BF16 CPUID.(EAX=7,ECX=0):EDX[bit 22] +- AVX512_FP16 CPUID.(EAX=7,ECX=0):EDX[bit 23] +- AMX-TILE CPUID.(EAX=7,ECX=0):EDX[bit 24] +- AMX-INT8 CPUID.(EAX=7,ECX=0):EDX[bit 25] +- AVX512_BF16 CPUID.(EAX=7,ECX=1):EAX[bit 5] +- fast zero-length MOVSB CPUID.(EAX=7,ECX=1):EAX[bit 10] +- fast short CMPSB, SCASB CPUID.(EAX=7,ECX=1):EAX[bit 12] +- AMX-FP16 CPUID.(EAX=7,ECX=1):EAX[bit 21] +- PREFETCHI CPUID.(EAX=7,ECX=1):EDX[bit 14] +- XFD CPUID.(EAX=0xD,ECX=1):EAX[bit 4] +- EPT_PAGE_WALK_LENGTH_5 VMX_EPT_VPID_CAP(0x48c)[bit 7] + +Add all features of GraniteRapids CPU model except above features to +SierraForest CPU model. + +SierraForest doesn’t support TSX and RTM but supports TAA_NO. When RTM is +not enabled in host, KVM will not report TAA_NO. So, just don't include +TAA_NO in SierraForest CPU model. + +[1] https://cdrdv2.intel.com/v1/dl/getContent/671368 + +Intel-SIG: commit 6e82d3b62207 target/i386: Add new CPU model SierraForest. +Add SRF new ISAs backporting + +Reviewed-by: Zhao Liu +Reviewed-by: Xiaoyao Li +Signed-off-by: Tao Su +Message-ID: <20240320021044.508263-1-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 126 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index a66e5a3..8131c5b 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -4100,6 +4100,132 @@ static const X86CPUDefinition builtin_x86_defs[] = { + }, + }, + { ++ .name = "SierraForest", ++ .level = 0x23, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 175, ++ .stepping = 0, ++ /* ++ * please keep the ascending order so that we can have a clear view of ++ * bit position of each feature. ++ */ ++ .features[FEAT_1_EDX] = ++ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | ++ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | ++ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | ++ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | ++ CPUID_SSE | CPUID_SSE2, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | ++ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | ++ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | ++ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES | ++ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | ++ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, ++ .features[FEAT_8000_0008_EBX] = ++ CPUID_8000_0008_EBX_WBNOINVD, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | ++ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | ++ CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | ++ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB | ++ CPUID_7_0_EBX_SHA_NI, ++ .features[FEAT_7_0_ECX] = ++ CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_GFNI | ++ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | ++ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE | ++ CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_ARCH_CAPABILITIES | ++ CPUID_7_0_EDX_SPEC_CTRL_SSBD, ++ .features[FEAT_ARCH_CAPABILITIES] = ++ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | ++ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | ++ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_SBDR_SSDP_NO | ++ MSR_ARCH_CAP_FBSDP_NO | MSR_ARCH_CAP_PSDP_NO | ++ MSR_ARCH_CAP_PBRSB_NO, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES, ++ .features[FEAT_6_EAX] = ++ CPUID_6_EAX_ARAT, ++ .features[FEAT_7_1_EAX] = ++ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_CMPCCXADD | ++ CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_AVX_IFMA, ++ .features[FEAT_7_1_EDX] = ++ CPUID_7_1_EDX_AVX_VNNI_INT8 | CPUID_7_1_EDX_AVX_NE_CONVERT, ++ .features[FEAT_7_2_EDX] = ++ CPUID_7_2_EDX_MCDT_NO, ++ .features[FEAT_VMX_BASIC] = ++ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS, ++ .features[FEAT_VMX_ENTRY_CTLS] = ++ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE | ++ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | ++ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER, ++ .features[FEAT_VMX_EPT_VPID_CAPS] = ++ MSR_VMX_EPT_EXECONLY | MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | ++ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB | ++ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS | ++ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | ++ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | ++ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | ++ MSR_VMX_EPT_INVVPID_ALL_CONTEXT | ++ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, ++ .features[FEAT_VMX_EXIT_CTLS] = ++ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | ++ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | ++ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT | ++ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | ++ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, ++ .features[FEAT_VMX_MISC] = ++ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT | ++ MSR_VMX_MISC_VMWRITE_VMEXIT, ++ .features[FEAT_VMX_PINBASED_CTLS] = ++ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING | ++ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER | ++ VMX_PIN_BASED_POSTED_INTR, ++ .features[FEAT_VMX_PROCBASED_CTLS] = ++ VMX_CPU_BASED_VIRTUAL_INTR_PENDING | ++ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | ++ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | ++ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | ++ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | ++ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | ++ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING | ++ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | ++ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG | ++ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | ++ VMX_CPU_BASED_PAUSE_EXITING | ++ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, ++ .features[FEAT_VMX_SECONDARY_CTLS] = ++ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | ++ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC | ++ VMX_SECONDARY_EXEC_RDTSCP | ++ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | ++ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING | ++ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | ++ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | ++ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | ++ VMX_SECONDARY_EXEC_RDRAND_EXITING | ++ VMX_SECONDARY_EXEC_ENABLE_INVPCID | ++ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | ++ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML | ++ VMX_SECONDARY_EXEC_XSAVES, ++ .features[FEAT_VMX_VMFUNC] = ++ MSR_VMX_VMFUNC_EPT_SWITCHING, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Xeon Processor (SierraForest)", ++ .versions = (X86CPUVersionDefinition[]) { ++ { .version = 1 }, ++ { /* end of list */ }, ++ }, ++ }, ++ { + .name = "Denverton", + .level = 21, + .vendor = CPUID_VENDOR_INTEL, +-- +1.8.3.1 + diff --git a/0147-target-i386-Export-RFDS-bit-to-guests.patch b/0147-target-i386-Export-RFDS-bit-to-guests.patch new file mode 100644 index 0000000000000000000000000000000000000000..6ceba48ec18c70224948f4187bdcb39102410de9 --- /dev/null +++ b/0147-target-i386-Export-RFDS-bit-to-guests.patch @@ -0,0 +1,47 @@ +From 86b65efe45023109b446d1f12aee72cc1dbc12fc Mon Sep 17 00:00:00 2001 +From: Pawan Gupta +Date: Wed, 13 Mar 2024 07:53:23 -0700 +Subject: [PATCH 157/293] target/i386: Export RFDS bit to guests + +commit 41bdd9812863c150284a9339a048ed88c40f4df7 upstream. + +Register File Data Sampling (RFDS) is a CPU side-channel vulnerability +that may expose stale register value. CPUs that set RFDS_NO bit in MSR +IA32_ARCH_CAPABILITIES indicate that they are not vulnerable to RFDS. +Similarly, RFDS_CLEAR indicates that CPU is affected by RFDS, and has +the microcode to help mitigate RFDS. + +Make RFDS_CLEAR and RFDS_NO bits available to guests. + +Intel-SIG: commit 41bdd9812863 target/i386: Export RFDS bit to guests. +Add SRF new ISAs backporting + +Signed-off-by: Pawan Gupta +Reviewed-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Message-ID: <9a38877857392b5c2deae7e7db1b170d15510314.1710341348.git.pawan.kumar.gupta@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 8131c5b..5c0dfee 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1157,8 +1157,8 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, "sbdr-ssdp-no", "fbsdp-no", "psdp-no", + NULL, "fb-clear", NULL, NULL, + NULL, NULL, NULL, NULL, +- "pbrsb-no", NULL, "gds-no", NULL, +- NULL, NULL, NULL, NULL, ++ "pbrsb-no", NULL, "gds-no", "rfds-no", ++ "rfds-clear", NULL, NULL, NULL, + }, + .msr = { + .index = MSR_IA32_ARCH_CAPABILITIES, +-- +1.8.3.1 + diff --git a/0003-hw-loongarch-virt-Align-high-memory-base-address-wit.patch b/0148-hw-loongarch-virt-Align-high-memory-base-address-wit.patch similarity index 86% rename from 0003-hw-loongarch-virt-Align-high-memory-base-address-wit.patch rename to 0148-hw-loongarch-virt-Align-high-memory-base-address-wit.patch index d7b1513f1ffd9645f2d844fc031d797531799b61..f3c50fcff78e535db57d54bbb68d3a8a83084696 100644 --- a/0003-hw-loongarch-virt-Align-high-memory-base-address-wit.patch +++ b/0148-hw-loongarch-virt-Align-high-memory-base-address-wit.patch @@ -1,8 +1,8 @@ -From 70e7ffec16e91138309ad3f76588cbd10c084394 Mon Sep 17 00:00:00 2001 +From 23cd527ecf10132eac9aad08e1930c249f17cfa1 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Mon, 27 Nov 2023 12:02:31 +0800 -Subject: [PATCH] hw/loongarch/virt: Align high memory base address with - super page size +Subject: [PATCH 158/293] hw/loongarch/virt: Align high memory base address + with super page size With LoongArch virt machine, there is low memory space with region 0--0x10000000, and high memory space with started from 0x90000000. @@ -22,7 +22,7 @@ Signed-off-by: Song Gao 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h -index 674f4655e0..db0831b471 100644 +index 674f465..db0831b 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -25,7 +25,7 @@ @@ -35,5 +35,5 @@ index 674f4655e0..db0831b471 100644 #define VIRT_GED_MEM_ADDR (VIRT_GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN) #define VIRT_GED_REG_ADDR (VIRT_GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN) -- -2.33.0 +1.8.3.1 diff --git a/0004-target-loongarch-Add-timer-information-dump-support.patch b/0149-target-loongarch-Add-timer-information-dump-support.patch similarity index 86% rename from 0004-target-loongarch-Add-timer-information-dump-support.patch rename to 0149-target-loongarch-Add-timer-information-dump-support.patch index 1558ba2b9e2ed7817497dc2b948553d46ea976bb..06ac33ac3396047ab04124a3fb1d15c682435a23 100644 --- a/0004-target-loongarch-Add-timer-information-dump-support.patch +++ b/0149-target-loongarch-Add-timer-information-dump-support.patch @@ -1,7 +1,7 @@ -From 8a43c9379651fbf9d015240d6dc7c4b90ce98683 Mon Sep 17 00:00:00 2001 +From 289d5c3c03aa20a3bdb40b466ee320a15b693a95 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 6 Dec 2023 16:18:39 +0800 -Subject: [PATCH] target/loongarch: Add timer information dump support +Subject: [PATCH 159/293] target/loongarch: Add timer information dump support Timer emulation sometimes is problematic especially when vm is running in kvm mode. This patch adds registers dump support relative with timer @@ -16,7 +16,7 @@ Signed-off-by: Song Gao 1 file changed, 2 insertions(+) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c -index fc075952e6..db9a421cc4 100644 +index fc07595..db9a421 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -762,6 +762,8 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) @@ -29,5 +29,5 @@ index fc075952e6..db9a421cc4 100644 /* fpr */ if (flags & CPU_DUMP_FPU) { -- -2.33.0 +1.8.3.1 diff --git a/0005-target-loongarch-meson-move-gdbstub.c-to-loongarch.s.patch b/0150-target-loongarch-meson-move-gdbstub.c-to-loongarch.s.patch similarity index 85% rename from 0005-target-loongarch-meson-move-gdbstub.c-to-loongarch.s.patch rename to 0150-target-loongarch-meson-move-gdbstub.c-to-loongarch.s.patch index 7e5f0a94a021895358ac032bc2c63a6b38aafddf..2ce4cf9e72bd6f4c29de89f07245880cb3b678a5 100644 --- a/0005-target-loongarch-meson-move-gdbstub.c-to-loongarch.s.patch +++ b/0150-target-loongarch-meson-move-gdbstub.c-to-loongarch.s.patch @@ -1,7 +1,8 @@ -From ae65e1281aa67713bde6bce323a3a8d06f27c636 Mon Sep 17 00:00:00 2001 +From 3ccdbe903cdb4d4b9b9bfc4ccacd3b5e94d9ec8f Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 2 Jan 2024 10:01:59 +0800 -Subject: [PATCH] target/loongarch/meson: move gdbstub.c to loongarch.ss +Subject: [PATCH 160/293] target/loongarch/meson: move gdbstub.c to + loongarch.ss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -17,7 +18,7 @@ Message-Id: <20240102020200.3462097-1-gaosong@loongson.cn> 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build -index 18e8191e2b..b3a0fb12fb 100644 +index 18e8191..b3a0fb1 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -3,6 +3,7 @@ gen = decodetree.process('insns.decode') @@ -37,5 +38,5 @@ index 18e8191e2b..b3a0fb12fb 100644 )) loongarch_tcg_ss.add(zlib) -- -2.33.0 +1.8.3.1 diff --git a/0151-target-loongarch-move-translate-modules-to-tcg.patch b/0151-target-loongarch-move-translate-modules-to-tcg.patch new file mode 100644 index 0000000000000000000000000000000000000000..e6366aedb407f97156cfb6caf516eeaf56ff73d3 --- /dev/null +++ b/0151-target-loongarch-move-translate-modules-to-tcg.patch @@ -0,0 +1,27885 @@ +From 9af01b78fb73fa1d5ac165d089e32a2de6483497 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Tue, 2 Jan 2024 10:02:00 +0800 +Subject: [PATCH 161/293] target/loongarch: move translate modules to tcg/ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce the target/loongarch/tcg directory. Its purpose is to hold the TCG +code that is selected by CONFIG_TCG + +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Song Gao +Message-Id: <20240102020200.3462097-2-gaosong@loongson.cn> +--- + target/loongarch/constant_timer.c | 64 - + target/loongarch/csr_helper.c | 97 - + target/loongarch/fpu_helper.c | 879 ---- + target/loongarch/insn_trans/trans_arith.c.inc | 304 -- + target/loongarch/insn_trans/trans_atomic.c.inc | 111 - + target/loongarch/insn_trans/trans_bit.c.inc | 208 - + target/loongarch/insn_trans/trans_branch.c.inc | 84 - + target/loongarch/insn_trans/trans_extra.c.inc | 107 - + target/loongarch/insn_trans/trans_farith.c.inc | 207 - + target/loongarch/insn_trans/trans_fcmp.c.inc | 72 - + target/loongarch/insn_trans/trans_fcnv.c.inc | 33 - + target/loongarch/insn_trans/trans_fmemory.c.inc | 158 - + target/loongarch/insn_trans/trans_fmov.c.inc | 224 - + target/loongarch/insn_trans/trans_memory.c.inc | 194 - + target/loongarch/insn_trans/trans_privileged.c.inc | 498 -- + target/loongarch/insn_trans/trans_shift.c.inc | 99 - + target/loongarch/insn_trans/trans_vec.c.inc | 5511 -------------------- + target/loongarch/iocsr_helper.c | 68 - + target/loongarch/meson.build | 15 +- + target/loongarch/op_helper.c | 140 - + target/loongarch/tcg/constant_timer.c | 64 + + target/loongarch/tcg/csr_helper.c | 97 + + target/loongarch/tcg/fpu_helper.c | 879 ++++ + target/loongarch/tcg/insn_trans/trans_arith.c.inc | 304 ++ + target/loongarch/tcg/insn_trans/trans_atomic.c.inc | 111 + + target/loongarch/tcg/insn_trans/trans_bit.c.inc | 208 + + target/loongarch/tcg/insn_trans/trans_branch.c.inc | 84 + + target/loongarch/tcg/insn_trans/trans_extra.c.inc | 107 + + target/loongarch/tcg/insn_trans/trans_farith.c.inc | 207 + + target/loongarch/tcg/insn_trans/trans_fcmp.c.inc | 72 + + target/loongarch/tcg/insn_trans/trans_fcnv.c.inc | 33 + + .../loongarch/tcg/insn_trans/trans_fmemory.c.inc | 158 + + target/loongarch/tcg/insn_trans/trans_fmov.c.inc | 224 + + target/loongarch/tcg/insn_trans/trans_memory.c.inc | 194 + + .../tcg/insn_trans/trans_privileged.c.inc | 498 ++ + target/loongarch/tcg/insn_trans/trans_shift.c.inc | 99 + + target/loongarch/tcg/insn_trans/trans_vec.c.inc | 5511 ++++++++++++++++++++ + target/loongarch/tcg/iocsr_helper.c | 68 + + target/loongarch/tcg/meson.build | 19 + + target/loongarch/tcg/op_helper.c | 140 + + target/loongarch/tcg/tlb_helper.c | 803 +++ + target/loongarch/tcg/translate.c | 370 ++ + target/loongarch/tcg/vec_helper.c | 3494 +++++++++++++ + target/loongarch/tlb_helper.c | 803 --- + target/loongarch/translate.c | 370 -- + target/loongarch/vec_helper.c | 3494 ------------- + 46 files changed, 13745 insertions(+), 13739 deletions(-) + delete mode 100644 target/loongarch/constant_timer.c + delete mode 100644 target/loongarch/csr_helper.c + delete mode 100644 target/loongarch/fpu_helper.c + delete mode 100644 target/loongarch/insn_trans/trans_arith.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_atomic.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_bit.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_branch.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_extra.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_farith.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_fcmp.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_fcnv.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_fmemory.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_fmov.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_memory.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_privileged.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_shift.c.inc + delete mode 100644 target/loongarch/insn_trans/trans_vec.c.inc + delete mode 100644 target/loongarch/iocsr_helper.c + delete mode 100644 target/loongarch/op_helper.c + create mode 100644 target/loongarch/tcg/constant_timer.c + create mode 100644 target/loongarch/tcg/csr_helper.c + create mode 100644 target/loongarch/tcg/fpu_helper.c + create mode 100644 target/loongarch/tcg/insn_trans/trans_arith.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_atomic.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_bit.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_branch.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_extra.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_farith.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_fcmp.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_fcnv.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_fmemory.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_fmov.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_memory.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_privileged.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_shift.c.inc + create mode 100644 target/loongarch/tcg/insn_trans/trans_vec.c.inc + create mode 100644 target/loongarch/tcg/iocsr_helper.c + create mode 100644 target/loongarch/tcg/meson.build + create mode 100644 target/loongarch/tcg/op_helper.c + create mode 100644 target/loongarch/tcg/tlb_helper.c + create mode 100644 target/loongarch/tcg/translate.c + create mode 100644 target/loongarch/tcg/vec_helper.c + delete mode 100644 target/loongarch/tlb_helper.c + delete mode 100644 target/loongarch/translate.c + delete mode 100644 target/loongarch/vec_helper.c + +diff --git a/target/loongarch/constant_timer.c b/target/loongarch/constant_timer.c +deleted file mode 100644 +index 1851f53..0000000 +--- a/target/loongarch/constant_timer.c ++++ /dev/null +@@ -1,64 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * QEMU LoongArch constant timer support +- * +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-#include "qemu/osdep.h" +-#include "qemu/timer.h" +-#include "cpu.h" +-#include "internals.h" +-#include "cpu-csr.h" +- +-#define TIMER_PERIOD 10 /* 10 ns period for 100 MHz frequency */ +-#define CONSTANT_TIMER_TICK_MASK 0xfffffffffffcUL +-#define CONSTANT_TIMER_ENABLE 0x1UL +- +-uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu) +-{ +- return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD; +-} +- +-uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu) +-{ +- uint64_t now, expire; +- +- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +- expire = timer_expire_time_ns(&cpu->timer); +- +- return (expire - now) / TIMER_PERIOD; +-} +- +-void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, +- uint64_t value) +-{ +- CPULoongArchState *env = &cpu->env; +- uint64_t now, next; +- +- env->CSR_TCFG = value; +- if (value & CONSTANT_TIMER_ENABLE) { +- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +- next = now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; +- timer_mod(&cpu->timer, next); +- } else { +- timer_del(&cpu->timer); +- } +-} +- +-void loongarch_constant_timer_cb(void *opaque) +-{ +- LoongArchCPU *cpu = opaque; +- CPULoongArchState *env = &cpu->env; +- uint64_t now, next; +- +- if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) { +- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +- next = now + (env->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; +- timer_mod(&cpu->timer, next); +- } else { +- env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0); +- } +- +- loongarch_cpu_set_irq(opaque, IRQ_TIMER, 1); +-} +diff --git a/target/loongarch/csr_helper.c b/target/loongarch/csr_helper.c +deleted file mode 100644 +index 5534155..0000000 +--- a/target/loongarch/csr_helper.c ++++ /dev/null +@@ -1,97 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * LoongArch emulation helpers for CSRs +- * +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-#include "qemu/osdep.h" +-#include "qemu/main-loop.h" +-#include "cpu.h" +-#include "internals.h" +-#include "qemu/host-utils.h" +-#include "exec/helper-proto.h" +-#include "exec/exec-all.h" +-#include "exec/cpu_ldst.h" +-#include "hw/irq.h" +-#include "cpu-csr.h" +- +-target_ulong helper_csrrd_pgd(CPULoongArchState *env) +-{ +- int64_t v; +- +- if (env->CSR_TLBRERA & 0x1) { +- v = env->CSR_TLBRBADV; +- } else { +- v = env->CSR_BADV; +- } +- +- if ((v >> 63) & 0x1) { +- v = env->CSR_PGDH; +- } else { +- v = env->CSR_PGDL; +- } +- +- return v; +-} +- +-target_ulong helper_csrrd_cpuid(CPULoongArchState *env) +-{ +- LoongArchCPU *lac = env_archcpu(env); +- +- env->CSR_CPUID = CPU(lac)->cpu_index; +- +- return env->CSR_CPUID; +-} +- +-target_ulong helper_csrrd_tval(CPULoongArchState *env) +-{ +- LoongArchCPU *cpu = env_archcpu(env); +- +- return cpu_loongarch_get_constant_timer_ticks(cpu); +-} +- +-target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) +-{ +- int64_t old_v = env->CSR_ESTAT; +- +- /* Only IS[1:0] can be written */ +- env->CSR_ESTAT = deposit64(env->CSR_ESTAT, 0, 2, val); +- +- return old_v; +-} +- +-target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val) +-{ +- int64_t old_v = env->CSR_ASID; +- +- /* Only ASID filed of CSR_ASID can be written */ +- env->CSR_ASID = deposit64(env->CSR_ASID, 0, 10, val); +- if (old_v != env->CSR_ASID) { +- tlb_flush(env_cpu(env)); +- } +- return old_v; +-} +- +-target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val) +-{ +- LoongArchCPU *cpu = env_archcpu(env); +- int64_t old_v = env->CSR_TCFG; +- +- cpu_loongarch_store_constant_timer_config(cpu, val); +- +- return old_v; +-} +- +-target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val) +-{ +- LoongArchCPU *cpu = env_archcpu(env); +- int64_t old_v = 0; +- +- if (val & 0x1) { +- qemu_mutex_lock_iothread(); +- loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0); +- qemu_mutex_unlock_iothread(); +- } +- return old_v; +-} +diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c +deleted file mode 100644 +index f6753c5..0000000 +--- a/target/loongarch/fpu_helper.c ++++ /dev/null +@@ -1,879 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * LoongArch float point emulation helpers for QEMU +- * +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-#include "qemu/osdep.h" +-#include "cpu.h" +-#include "exec/helper-proto.h" +-#include "exec/exec-all.h" +-#include "exec/cpu_ldst.h" +-#include "fpu/softfloat.h" +-#include "internals.h" +- +-static inline uint64_t nanbox_s(float32 fp) +-{ +- return fp | MAKE_64BIT_MASK(32, 32); +-} +- +-/* Convert loongarch rounding mode in fcsr0 to IEEE library */ +-static const FloatRoundMode ieee_rm[4] = { +- float_round_nearest_even, +- float_round_to_zero, +- float_round_up, +- float_round_down +-}; +- +-void restore_fp_status(CPULoongArchState *env) +-{ +- set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3], +- &env->fp_status); +- set_flush_to_zero(0, &env->fp_status); +-} +- +-int ieee_ex_to_loongarch(int xcpt) +-{ +- int ret = 0; +- if (xcpt & float_flag_invalid) { +- ret |= FP_INVALID; +- } +- if (xcpt & float_flag_overflow) { +- ret |= FP_OVERFLOW; +- } +- if (xcpt & float_flag_underflow) { +- ret |= FP_UNDERFLOW; +- } +- if (xcpt & float_flag_divbyzero) { +- ret |= FP_DIV0; +- } +- if (xcpt & float_flag_inexact) { +- ret |= FP_INEXACT; +- } +- return ret; +-} +- +-static void update_fcsr0_mask(CPULoongArchState *env, uintptr_t pc, int mask) +-{ +- int flags = get_float_exception_flags(&env->fp_status); +- +- set_float_exception_flags(0, &env->fp_status); +- +- flags &= ~mask; +- +- if (!flags) { +- SET_FP_CAUSE(env->fcsr0, flags); +- return; +- } else { +- flags = ieee_ex_to_loongarch(flags); +- SET_FP_CAUSE(env->fcsr0, flags); +- } +- +- if (GET_FP_ENABLES(env->fcsr0) & flags) { +- do_raise_exception(env, EXCCODE_FPE, pc); +- } else { +- UPDATE_FP_FLAGS(env->fcsr0, flags); +- } +-} +- +-static void update_fcsr0(CPULoongArchState *env, uintptr_t pc) +-{ +- update_fcsr0_mask(env, pc, 0); +-} +- +-uint64_t helper_fadd_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_add((uint32_t)fj, (uint32_t)fk, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fadd_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = float64_add(fj, fk, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fsub_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_sub((uint32_t)fj, (uint32_t)fk, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fsub_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = float64_sub(fj, fk, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmul_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_mul((uint32_t)fj, (uint32_t)fk, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmul_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = float64_mul(fj, fk, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fdiv_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_div((uint32_t)fj, (uint32_t)fk, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fdiv_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = float64_div(fj, fk, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmax_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_maxnum((uint32_t)fj, (uint32_t)fk, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmax_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = float64_maxnum(fj, fk, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmin_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_minnum((uint32_t)fj, (uint32_t)fk, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmin_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = float64_minnum(fj, fk, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmaxa_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_maxnummag((uint32_t)fj, +- (uint32_t)fk, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmaxa_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = float64_maxnummag(fj, fk, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmina_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_minnummag((uint32_t)fj, +- (uint32_t)fk, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmina_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- +- fd = float64_minnummag(fj, fk, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fscaleb_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- int32_t n = (int32_t)fk; +- +- fd = nanbox_s(float32_scalbn((uint32_t)fj, +- n > 0x200 ? 0x200 : +- n < -0x200 ? -0x200 : n, +- &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fscaleb_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) +-{ +- uint64_t fd; +- int64_t n = (int64_t)fk; +- +- fd = float64_scalbn(fj, +- n > 0x1000 ? 0x1000 : +- n < -0x1000 ? -0x1000 : n, +- &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fsqrt_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_sqrt((uint32_t)fj, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fsqrt_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = float64_sqrt(fj, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_frecip_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_div(float32_one, (uint32_t)fj, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_frecip_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = float64_div(float64_one, fj, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_frsqrt_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- uint32_t fp; +- +- fp = float32_sqrt((uint32_t)fj, &env->fp_status); +- fd = nanbox_s(float32_div(float32_one, fp, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_frsqrt_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fp, fd; +- +- fp = float64_sqrt(fj, &env->fp_status); +- fd = float64_div(float64_one, fp, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_flogb_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- uint32_t fp; +- float_status *status = &env->fp_status; +- FloatRoundMode old_mode = get_float_rounding_mode(status); +- +- set_float_rounding_mode(float_round_down, status); +- fp = float32_log2((uint32_t)fj, status); +- fd = nanbox_s(float32_round_to_int(fp, status)); +- set_float_rounding_mode(old_mode, status); +- update_fcsr0_mask(env, GETPC(), float_flag_inexact); +- return fd; +-} +- +-uint64_t helper_flogb_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- float_status *status = &env->fp_status; +- FloatRoundMode old_mode = get_float_rounding_mode(status); +- +- set_float_rounding_mode(float_round_down, status); +- fd = float64_log2(fj, status); +- fd = float64_round_to_int(fd, status); +- set_float_rounding_mode(old_mode, status); +- update_fcsr0_mask(env, GETPC(), float_flag_inexact); +- return fd; +-} +- +-uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj) +-{ +- float32 f = fj; +- bool sign = float32_is_neg(f); +- +- if (float32_is_infinity(f)) { +- return sign ? 1 << 2 : 1 << 6; +- } else if (float32_is_zero(f)) { +- return sign ? 1 << 5 : 1 << 9; +- } else if (float32_is_zero_or_denormal(f)) { +- return sign ? 1 << 4 : 1 << 8; +- } else if (float32_is_any_nan(f)) { +- float_status s = { }; /* for snan_bit_is_one */ +- return float32_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0; +- } else { +- return sign ? 1 << 3 : 1 << 7; +- } +-} +- +-uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj) +-{ +- float64 f = fj; +- bool sign = float64_is_neg(f); +- +- if (float64_is_infinity(f)) { +- return sign ? 1 << 2 : 1 << 6; +- } else if (float64_is_zero(f)) { +- return sign ? 1 << 5 : 1 << 9; +- } else if (float64_is_zero_or_denormal(f)) { +- return sign ? 1 << 4 : 1 << 8; +- } else if (float64_is_any_nan(f)) { +- float_status s = { }; /* for snan_bit_is_one */ +- return float64_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0; +- } else { +- return sign ? 1 << 3 : 1 << 7; +- } +-} +- +-uint64_t helper_fmuladd_s(CPULoongArchState *env, uint64_t fj, +- uint64_t fk, uint64_t fa, uint32_t flag) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float32_muladd((uint32_t)fj, (uint32_t)fk, +- (uint32_t)fa, flag, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fmuladd_d(CPULoongArchState *env, uint64_t fj, +- uint64_t fk, uint64_t fa, uint32_t flag) +-{ +- uint64_t fd; +- +- fd = float64_muladd(fj, fk, fa, flag, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-static uint64_t fcmp_common(CPULoongArchState *env, FloatRelation cmp, +- uint32_t flags) +-{ +- bool ret; +- +- switch (cmp) { +- case float_relation_less: +- ret = (flags & FCMP_LT); +- break; +- case float_relation_equal: +- ret = (flags & FCMP_EQ); +- break; +- case float_relation_greater: +- ret = (flags & FCMP_GT); +- break; +- case float_relation_unordered: +- ret = (flags & FCMP_UN); +- break; +- default: +- g_assert_not_reached(); +- } +- update_fcsr0(env, GETPC()); +- +- return ret; +-} +- +-/* fcmp_cXXX_s */ +-uint64_t helper_fcmp_c_s(CPULoongArchState *env, uint64_t fj, +- uint64_t fk, uint32_t flags) +-{ +- FloatRelation cmp = float32_compare_quiet((uint32_t)fj, +- (uint32_t)fk, &env->fp_status); +- return fcmp_common(env, cmp, flags); +-} +- +-/* fcmp_sXXX_s */ +-uint64_t helper_fcmp_s_s(CPULoongArchState *env, uint64_t fj, +- uint64_t fk, uint32_t flags) +-{ +- FloatRelation cmp = float32_compare((uint32_t)fj, +- (uint32_t)fk, &env->fp_status); +- return fcmp_common(env, cmp, flags); +-} +- +-/* fcmp_cXXX_d */ +-uint64_t helper_fcmp_c_d(CPULoongArchState *env, uint64_t fj, +- uint64_t fk, uint32_t flags) +-{ +- FloatRelation cmp = float64_compare_quiet(fj, fk, &env->fp_status); +- return fcmp_common(env, cmp, flags); +-} +- +-/* fcmp_sXXX_d */ +-uint64_t helper_fcmp_s_d(CPULoongArchState *env, uint64_t fj, +- uint64_t fk, uint32_t flags) +-{ +- FloatRelation cmp = float64_compare(fj, fk, &env->fp_status); +- return fcmp_common(env, cmp, flags); +-} +- +-/* floating point conversion */ +-uint64_t helper_fcvt_s_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = nanbox_s(float64_to_float32(fj, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_fcvt_d_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = float32_to_float64((uint32_t)fj, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ffint_s_w(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = nanbox_s(int32_to_float32((int32_t)fj, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ffint_s_l(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = nanbox_s(int64_to_float32(fj, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ffint_d_w(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = int32_to_float64((int32_t)fj, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ffint_d_l(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = int64_to_float64(fj, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_frint_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = (uint64_t)(float32_round_to_int((uint32_t)fj, &env->fp_status)); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_frint_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = float64_round_to_int(fj, &env->fp_status); +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrm_l_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_down, &env->fp_status); +- fd = float64_to_int64(fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float64_is_any_nan(fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrm_l_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_down, &env->fp_status); +- fd = float32_to_int64((uint32_t)fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float32_is_any_nan((uint32_t)fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrm_w_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_down, &env->fp_status); +- fd = (uint64_t)float64_to_int32(fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float64_is_any_nan(fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrm_w_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_down, &env->fp_status); +- fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float32_is_any_nan((uint32_t)fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrp_l_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_up, &env->fp_status); +- fd = float64_to_int64(fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float64_is_any_nan(fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrp_l_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_up, &env->fp_status); +- fd = float32_to_int64((uint32_t)fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float32_is_any_nan((uint32_t)fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrp_w_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_up, &env->fp_status); +- fd = (uint64_t)float64_to_int32(fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float64_is_any_nan(fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrp_w_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_up, &env->fp_status); +- fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float32_is_any_nan((uint32_t)fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrz_l_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- fd = float64_to_int64_round_to_zero(fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float64_is_any_nan(fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrz_l_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- fd = float32_to_int64_round_to_zero((uint32_t)fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float32_is_any_nan((uint32_t)fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrz_w_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- fd = (uint64_t)float64_to_int32_round_to_zero(fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float64_is_any_nan(fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrz_w_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint32_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- fd = float32_to_int32_round_to_zero((uint32_t)fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float32_is_any_nan((uint32_t)fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return (uint64_t)fd; +-} +- +-uint64_t helper_ftintrne_l_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_nearest_even, &env->fp_status); +- fd = float64_to_int64(fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float64_is_any_nan(fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrne_l_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_nearest_even, &env->fp_status); +- fd = float32_to_int64((uint32_t)fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float32_is_any_nan((uint32_t)fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrne_w_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_nearest_even, &env->fp_status); +- fd = (uint64_t)float64_to_int32(fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float64_is_any_nan(fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftintrne_w_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint32_t fd; +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); +- +- set_float_rounding_mode(float_round_nearest_even, &env->fp_status); +- fd = float32_to_int32((uint32_t)fj, &env->fp_status); +- set_float_rounding_mode(old_mode, &env->fp_status); +- +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float32_is_any_nan((uint32_t)fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return (uint64_t)fd; +-} +- +-uint64_t helper_ftint_l_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = float64_to_int64(fj, &env->fp_status); +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float64_is_any_nan(fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftint_l_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = float32_to_int64((uint32_t)fj, &env->fp_status); +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float32_is_any_nan((uint32_t)fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftint_w_s(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float32_is_any_nan((uint32_t)fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-uint64_t helper_ftint_w_d(CPULoongArchState *env, uint64_t fj) +-{ +- uint64_t fd; +- +- fd = (uint64_t)float64_to_int32(fj, &env->fp_status); +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { +- if (float64_is_any_nan(fj)) { +- fd = 0; +- } +- } +- update_fcsr0(env, GETPC()); +- return fd; +-} +- +-void helper_set_rounding_mode(CPULoongArchState *env) +-{ +- set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3], +- &env->fp_status); +-} +diff --git a/target/loongarch/insn_trans/trans_arith.c.inc b/target/loongarch/insn_trans/trans_arith.c.inc +deleted file mode 100644 +index 2be057e..0000000 +--- a/target/loongarch/insn_trans/trans_arith.c.inc ++++ /dev/null +@@ -1,304 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-static bool gen_rrr(DisasContext *ctx, arg_rrr *a, +- DisasExtend src1_ext, DisasExtend src2_ext, +- DisasExtend dst_ext, void (*func)(TCGv, TCGv, TCGv)) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, dst_ext); +- TCGv src1 = gpr_src(ctx, a->rj, src1_ext); +- TCGv src2 = gpr_src(ctx, a->rk, src2_ext); +- +- func(dest, src1, src2); +- gen_set_gpr(a->rd, dest, dst_ext); +- +- return true; +-} +- +-static bool gen_rri_v(DisasContext *ctx, arg_rr_i *a, +- DisasExtend src_ext, DisasExtend dst_ext, +- void (*func)(TCGv, TCGv, TCGv)) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, dst_ext); +- TCGv src1 = gpr_src(ctx, a->rj, src_ext); +- TCGv src2 = tcg_constant_tl(a->imm); +- +- func(dest, src1, src2); +- gen_set_gpr(a->rd, dest, dst_ext); +- +- return true; +-} +- +-static bool gen_rri_c(DisasContext *ctx, arg_rr_i *a, +- DisasExtend src_ext, DisasExtend dst_ext, +- void (*func)(TCGv, TCGv, target_long)) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, dst_ext); +- TCGv src1 = gpr_src(ctx, a->rj, src_ext); +- +- func(dest, src1, a->imm); +- gen_set_gpr(a->rd, dest, dst_ext); +- +- return true; +-} +- +-static bool gen_rrr_sa(DisasContext *ctx, arg_rrr_sa *a, +- DisasExtend src_ext, DisasExtend dst_ext, +- void (*func)(TCGv, TCGv, TCGv, target_long)) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, dst_ext); +- TCGv src1 = gpr_src(ctx, a->rj, src_ext); +- TCGv src2 = gpr_src(ctx, a->rk, src_ext); +- +- func(dest, src1, src2, a->sa); +- gen_set_gpr(a->rd, dest, dst_ext); +- +- return true; +-} +- +-static bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- +- tcg_gen_movi_tl(dest, a->imm << 12); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static bool gen_pc(DisasContext *ctx, arg_r_i *a, +- target_ulong (*func)(target_ulong, int)) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- target_ulong addr = make_address_pc(ctx, func(ctx->base.pc_next, a->imm)); +- +- tcg_gen_movi_tl(dest, addr); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static void gen_slt(TCGv dest, TCGv src1, TCGv src2) +-{ +- tcg_gen_setcond_tl(TCG_COND_LT, dest, src1, src2); +-} +- +-static void gen_sltu(TCGv dest, TCGv src1, TCGv src2) +-{ +- tcg_gen_setcond_tl(TCG_COND_LTU, dest, src1, src2); +-} +- +-static void gen_mulh_w(TCGv dest, TCGv src1, TCGv src2) +-{ +- tcg_gen_mul_i64(dest, src1, src2); +- tcg_gen_sari_i64(dest, dest, 32); +-} +- +-static void gen_mulh_d(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv discard = tcg_temp_new(); +- tcg_gen_muls2_tl(discard, dest, src1, src2); +-} +- +-static void gen_mulh_du(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv discard = tcg_temp_new(); +- tcg_gen_mulu2_tl(discard, dest, src1, src2); +-} +- +-static void prep_divisor_d(TCGv ret, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- TCGv t1 = tcg_temp_new(); +- TCGv zero = tcg_constant_tl(0); +- +- /* +- * If min / -1, set the divisor to 1. +- * This avoids potential host overflow trap and produces min. +- * If x / 0, set the divisor to 1. +- * This avoids potential host overflow trap; +- * the required result is undefined. +- */ +- tcg_gen_setcondi_tl(TCG_COND_EQ, ret, src1, INT64_MIN); +- tcg_gen_setcondi_tl(TCG_COND_EQ, t0, src2, -1); +- tcg_gen_setcondi_tl(TCG_COND_EQ, t1, src2, 0); +- tcg_gen_and_tl(ret, ret, t0); +- tcg_gen_or_tl(ret, ret, t1); +- tcg_gen_movcond_tl(TCG_COND_NE, ret, ret, zero, ret, src2); +-} +- +-static void prep_divisor_du(TCGv ret, TCGv src2) +-{ +- TCGv zero = tcg_constant_tl(0); +- TCGv one = tcg_constant_tl(1); +- +- /* +- * If x / 0, set the divisor to 1. +- * This avoids potential host overflow trap; +- * the required result is undefined. +- */ +- tcg_gen_movcond_tl(TCG_COND_EQ, ret, src2, zero, one, src2); +-} +- +-static void gen_div_d(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- prep_divisor_d(t0, src1, src2); +- tcg_gen_div_tl(dest, src1, t0); +-} +- +-static void gen_rem_d(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- prep_divisor_d(t0, src1, src2); +- tcg_gen_rem_tl(dest, src1, t0); +-} +- +-static void gen_div_du(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- prep_divisor_du(t0, src2); +- tcg_gen_divu_tl(dest, src1, t0); +-} +- +-static void gen_rem_du(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- prep_divisor_du(t0, src2); +- tcg_gen_remu_tl(dest, src1, t0); +-} +- +-static void gen_div_w(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- /* We need not check for integer overflow for div_w. */ +- prep_divisor_du(t0, src2); +- tcg_gen_div_tl(dest, src1, t0); +-} +- +-static void gen_rem_w(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- /* We need not check for integer overflow for rem_w. */ +- prep_divisor_du(t0, src2); +- tcg_gen_rem_tl(dest, src1, t0); +-} +- +-static void gen_alsl(TCGv dest, TCGv src1, TCGv src2, target_long sa) +-{ +- TCGv t0 = tcg_temp_new(); +- tcg_gen_shli_tl(t0, src1, sa); +- tcg_gen_add_tl(dest, t0, src2); +-} +- +-static bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE); +- TCGv src2 = tcg_constant_tl(a->imm); +- +- if (!avail_64(ctx)) { +- return false; +- } +- +- tcg_gen_deposit_tl(dest, src1, src2, 32, 32); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = tcg_constant_tl(a->imm); +- +- if (!avail_64(ctx)) { +- return false; +- } +- +- tcg_gen_deposit_tl(dest, src1, src2, 52, 12); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static target_ulong gen_pcaddi(target_ulong pc, int imm) +-{ +- return pc + (imm << 2); +-} +- +-static target_ulong gen_pcalau12i(target_ulong pc, int imm) +-{ +- return (pc + (imm << 12)) & ~0xfff; +-} +- +-static target_ulong gen_pcaddu12i(target_ulong pc, int imm) +-{ +- return pc + (imm << 12); +-} +- +-static target_ulong gen_pcaddu18i(target_ulong pc, int imm) +-{ +- return pc + ((target_ulong)(imm) << 18); +-} +- +-static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- +- if (!avail_64(ctx)) { +- return false; +- } +- +- tcg_gen_addi_tl(dest, src1, a->imm << 16); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-TRANS(add_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl) +-TRANS(add_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl) +-TRANS(sub_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_sub_tl) +-TRANS(sub_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl) +-TRANS(and, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_and_tl) +-TRANS(or, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_or_tl) +-TRANS(xor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_xor_tl) +-TRANS(nor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_nor_tl) +-TRANS(andn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_andc_tl) +-TRANS(orn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_orc_tl) +-TRANS(slt, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_slt) +-TRANS(sltu, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sltu) +-TRANS(mul_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, tcg_gen_mul_tl) +-TRANS(mul_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl) +-TRANS(mulh_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, gen_mulh_w) +-TRANS(mulh_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, gen_mulh_w) +-TRANS(mulh_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_d) +-TRANS(mulh_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_du) +-TRANS(mulw_d_w, 64, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, tcg_gen_mul_tl) +-TRANS(mulw_d_wu, 64, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, tcg_gen_mul_tl) +-TRANS(div_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_div_w) +-TRANS(mod_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_rem_w) +-TRANS(div_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_div_du) +-TRANS(mod_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_rem_du) +-TRANS(div_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_d) +-TRANS(mod_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_d) +-TRANS(div_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_du) +-TRANS(mod_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_du) +-TRANS(slti, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_slt) +-TRANS(sltui, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_sltu) +-TRANS(addi_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_addi_tl) +-TRANS(addi_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_addi_tl) +-TRANS(alsl_w, ALL, gen_rrr_sa, EXT_NONE, EXT_SIGN, gen_alsl) +-TRANS(alsl_wu, 64, gen_rrr_sa, EXT_NONE, EXT_ZERO, gen_alsl) +-TRANS(alsl_d, 64, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_alsl) +-TRANS(pcaddi, ALL, gen_pc, gen_pcaddi) +-TRANS(pcalau12i, ALL, gen_pc, gen_pcalau12i) +-TRANS(pcaddu12i, ALL, gen_pc, gen_pcaddu12i) +-TRANS(pcaddu18i, 64, gen_pc, gen_pcaddu18i) +-TRANS(andi, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_andi_tl) +-TRANS(ori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_ori_tl) +-TRANS(xori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_xori_tl) +diff --git a/target/loongarch/insn_trans/trans_atomic.c.inc b/target/loongarch/insn_trans/trans_atomic.c.inc +deleted file mode 100644 +index 80c2e28..0000000 +--- a/target/loongarch/insn_trans/trans_atomic.c.inc ++++ /dev/null +@@ -1,111 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-static bool gen_ll(DisasContext *ctx, arg_rr_i *a, MemOp mop) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv t0 = make_address_i(ctx, src1, a->imm); +- +- tcg_gen_qemu_ld_i64(dest, t0, ctx->mem_idx, mop); +- tcg_gen_st_tl(t0, tcg_env, offsetof(CPULoongArchState, lladdr)); +- tcg_gen_st_tl(dest, tcg_env, offsetof(CPULoongArchState, llval)); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static bool gen_sc(DisasContext *ctx, arg_rr_i *a, MemOp mop) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rd, EXT_NONE); +- TCGv t0 = tcg_temp_new(); +- TCGv val = tcg_temp_new(); +- +- TCGLabel *l1 = gen_new_label(); +- TCGLabel *done = gen_new_label(); +- +- tcg_gen_addi_tl(t0, src1, a->imm); +- tcg_gen_brcond_tl(TCG_COND_EQ, t0, cpu_lladdr, l1); +- tcg_gen_movi_tl(dest, 0); +- tcg_gen_br(done); +- +- gen_set_label(l1); +- tcg_gen_mov_tl(val, src2); +- /* generate cmpxchg */ +- tcg_gen_atomic_cmpxchg_tl(t0, cpu_lladdr, cpu_llval, +- val, ctx->mem_idx, mop); +- tcg_gen_setcond_tl(TCG_COND_EQ, dest, t0, cpu_llval); +- gen_set_label(done); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static bool gen_am(DisasContext *ctx, arg_rrr *a, +- void (*func)(TCGv, TCGv, TCGv, TCGArg, MemOp), +- MemOp mop) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv val = gpr_src(ctx, a->rk, EXT_NONE); +- +- if (a->rd != 0 && (a->rj == a->rd || a->rk == a->rd)) { +- qemu_log_mask(LOG_GUEST_ERROR, +- "Warning: source register overlaps destination register" +- "in atomic insn at pc=0x" TARGET_FMT_lx "\n", +- ctx->base.pc_next - 4); +- return false; +- } +- +- addr = make_address_i(ctx, addr, 0); +- +- func(dest, addr, val, ctx->mem_idx, mop); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-TRANS(ll_w, ALL, gen_ll, MO_TESL) +-TRANS(sc_w, ALL, gen_sc, MO_TESL) +-TRANS(ll_d, 64, gen_ll, MO_TEUQ) +-TRANS(sc_d, 64, gen_sc, MO_TEUQ) +-TRANS(amswap_w, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +-TRANS(amswap_d, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +-TRANS(amadd_w, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +-TRANS(amadd_d, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +-TRANS(amand_w, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +-TRANS(amand_d, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +-TRANS(amor_w, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +-TRANS(amor_d, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +-TRANS(amxor_w, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +-TRANS(amxor_d, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +-TRANS(ammax_w, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +-TRANS(ammax_d, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +-TRANS(ammin_w, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +-TRANS(ammin_d, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +-TRANS(ammax_wu, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +-TRANS(ammax_du, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +-TRANS(ammin_wu, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +-TRANS(ammin_du, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +-TRANS(amswap_db_w, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +-TRANS(amswap_db_d, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +-TRANS(amadd_db_w, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +-TRANS(amadd_db_d, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +-TRANS(amand_db_w, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +-TRANS(amand_db_d, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +-TRANS(amor_db_w, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +-TRANS(amor_db_d, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +-TRANS(amxor_db_w, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +-TRANS(amxor_db_d, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +-TRANS(ammax_db_w, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +-TRANS(ammax_db_d, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +-TRANS(ammin_db_w, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +-TRANS(ammin_db_d, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +-TRANS(ammax_db_wu, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +-TRANS(ammax_db_du, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +-TRANS(ammin_db_wu, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +-TRANS(ammin_db_du, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +diff --git a/target/loongarch/insn_trans/trans_bit.c.inc b/target/loongarch/insn_trans/trans_bit.c.inc +deleted file mode 100644 +index ee5fa00..0000000 +--- a/target/loongarch/insn_trans/trans_bit.c.inc ++++ /dev/null +@@ -1,208 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-static bool gen_rr(DisasContext *ctx, arg_rr *a, +- DisasExtend src_ext, DisasExtend dst_ext, +- void (*func)(TCGv, TCGv)) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, dst_ext); +- TCGv src1 = gpr_src(ctx, a->rj, src_ext); +- +- func(dest, src1); +- gen_set_gpr(a->rd, dest, dst_ext); +- +- return true; +-} +- +-static void gen_bytepick_w(TCGv dest, TCGv src1, TCGv src2, target_long sa) +-{ +- tcg_gen_concat_tl_i64(dest, src1, src2); +- tcg_gen_sextract_i64(dest, dest, (32 - sa * 8), 32); +-} +- +-static void gen_bytepick_d(TCGv dest, TCGv src1, TCGv src2, target_long sa) +-{ +- tcg_gen_extract2_i64(dest, src1, src2, (64 - sa * 8)); +-} +- +-static bool gen_bstrins(DisasContext *ctx, arg_rr_ms_ls *a, +- DisasExtend dst_ext) +-{ +- TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- +- if (a->ls > a->ms) { +- return false; +- } +- +- tcg_gen_deposit_tl(dest, src1, src2, a->ls, a->ms - a->ls + 1); +- gen_set_gpr(a->rd, dest, dst_ext); +- return true; +-} +- +-static bool gen_bstrpick(DisasContext *ctx, arg_rr_ms_ls *a, +- DisasExtend dst_ext) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- +- if (a->ls > a->ms) { +- return false; +- } +- +- tcg_gen_extract_tl(dest, src1, a->ls, a->ms - a->ls + 1); +- gen_set_gpr(a->rd, dest, dst_ext); +- return true; +-} +- +-static void gen_clz_w(TCGv dest, TCGv src1) +-{ +- tcg_gen_clzi_tl(dest, src1, TARGET_LONG_BITS); +- tcg_gen_subi_tl(dest, dest, TARGET_LONG_BITS - 32); +-} +- +-static void gen_clo_w(TCGv dest, TCGv src1) +-{ +- tcg_gen_not_tl(dest, src1); +- tcg_gen_ext32u_tl(dest, dest); +- gen_clz_w(dest, dest); +-} +- +-static void gen_ctz_w(TCGv dest, TCGv src1) +-{ +- tcg_gen_ori_tl(dest, src1, (target_ulong)MAKE_64BIT_MASK(32, 32)); +- tcg_gen_ctzi_tl(dest, dest, TARGET_LONG_BITS); +-} +- +-static void gen_cto_w(TCGv dest, TCGv src1) +-{ +- tcg_gen_not_tl(dest, src1); +- gen_ctz_w(dest, dest); +-} +- +-static void gen_clz_d(TCGv dest, TCGv src1) +-{ +- tcg_gen_clzi_i64(dest, src1, TARGET_LONG_BITS); +-} +- +-static void gen_clo_d(TCGv dest, TCGv src1) +-{ +- tcg_gen_not_tl(dest, src1); +- gen_clz_d(dest, dest); +-} +- +-static void gen_ctz_d(TCGv dest, TCGv src1) +-{ +- tcg_gen_ctzi_tl(dest, src1, TARGET_LONG_BITS); +-} +- +-static void gen_cto_d(TCGv dest, TCGv src1) +-{ +- tcg_gen_not_tl(dest, src1); +- gen_ctz_d(dest, dest); +-} +- +-static void gen_revb_2w(TCGv dest, TCGv src1) +-{ +- tcg_gen_bswap64_i64(dest, src1); +- tcg_gen_rotri_i64(dest, dest, 32); +-} +- +-static void gen_revb_2h(TCGv dest, TCGv src1) +-{ +- TCGv mask = tcg_constant_tl(0x00FF00FF); +- TCGv t0 = tcg_temp_new(); +- TCGv t1 = tcg_temp_new(); +- +- tcg_gen_shri_tl(t0, src1, 8); +- tcg_gen_and_tl(t0, t0, mask); +- tcg_gen_and_tl(t1, src1, mask); +- tcg_gen_shli_tl(t1, t1, 8); +- tcg_gen_or_tl(dest, t0, t1); +-} +- +-static void gen_revb_4h(TCGv dest, TCGv src1) +-{ +- TCGv mask = tcg_constant_tl(0x00FF00FF00FF00FFULL); +- TCGv t0 = tcg_temp_new(); +- TCGv t1 = tcg_temp_new(); +- +- tcg_gen_shri_tl(t0, src1, 8); +- tcg_gen_and_tl(t0, t0, mask); +- tcg_gen_and_tl(t1, src1, mask); +- tcg_gen_shli_tl(t1, t1, 8); +- tcg_gen_or_tl(dest, t0, t1); +-} +- +-static void gen_revh_2w(TCGv dest, TCGv src1) +-{ +- TCGv_i64 t0 = tcg_temp_new_i64(); +- TCGv_i64 t1 = tcg_temp_new_i64(); +- TCGv_i64 mask = tcg_constant_i64(0x0000ffff0000ffffull); +- +- tcg_gen_shri_i64(t0, src1, 16); +- tcg_gen_and_i64(t1, src1, mask); +- tcg_gen_and_i64(t0, t0, mask); +- tcg_gen_shli_i64(t1, t1, 16); +- tcg_gen_or_i64(dest, t1, t0); +-} +- +-static void gen_revh_d(TCGv dest, TCGv src1) +-{ +- TCGv t0 = tcg_temp_new(); +- TCGv t1 = tcg_temp_new(); +- TCGv mask = tcg_constant_tl(0x0000FFFF0000FFFFULL); +- +- tcg_gen_shri_tl(t1, src1, 16); +- tcg_gen_and_tl(t1, t1, mask); +- tcg_gen_and_tl(t0, src1, mask); +- tcg_gen_shli_tl(t0, t0, 16); +- tcg_gen_or_tl(t0, t0, t1); +- tcg_gen_rotri_tl(dest, t0, 32); +-} +- +-static void gen_maskeqz(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv zero = tcg_constant_tl(0); +- +- tcg_gen_movcond_tl(TCG_COND_EQ, dest, src2, zero, zero, src1); +-} +- +-static void gen_masknez(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv zero = tcg_constant_tl(0); +- +- tcg_gen_movcond_tl(TCG_COND_NE, dest, src2, zero, zero, src1); +-} +- +-TRANS(ext_w_h, ALL, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext16s_tl) +-TRANS(ext_w_b, ALL, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext8s_tl) +-TRANS(clo_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_clo_w) +-TRANS(clz_w, ALL, gen_rr, EXT_ZERO, EXT_NONE, gen_clz_w) +-TRANS(cto_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_cto_w) +-TRANS(ctz_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_w) +-TRANS(clo_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_clo_d) +-TRANS(clz_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_clz_d) +-TRANS(cto_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_cto_d) +-TRANS(ctz_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_d) +-TRANS(revb_2h, ALL, gen_rr, EXT_NONE, EXT_SIGN, gen_revb_2h) +-TRANS(revb_4h, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revb_4h) +-TRANS(revb_2w, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revb_2w) +-TRANS(revb_d, 64, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_bswap64_i64) +-TRANS(revh_2w, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revh_2w) +-TRANS(revh_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revh_d) +-TRANS(bitrev_4b, ALL, gen_rr, EXT_ZERO, EXT_SIGN, gen_helper_bitswap) +-TRANS(bitrev_8b, 64, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitswap) +-TRANS(bitrev_w, ALL, gen_rr, EXT_NONE, EXT_SIGN, gen_helper_bitrev_w) +-TRANS(bitrev_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitrev_d) +-TRANS(maskeqz, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_maskeqz) +-TRANS(masknez, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez) +-TRANS(bytepick_w, ALL, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_w) +-TRANS(bytepick_d, 64, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_d) +-TRANS(bstrins_w, ALL, gen_bstrins, EXT_SIGN) +-TRANS(bstrins_d, 64, gen_bstrins, EXT_NONE) +-TRANS(bstrpick_w, ALL, gen_bstrpick, EXT_SIGN) +-TRANS(bstrpick_d, 64, gen_bstrpick, EXT_NONE) +diff --git a/target/loongarch/insn_trans/trans_branch.c.inc b/target/loongarch/insn_trans/trans_branch.c.inc +deleted file mode 100644 +index 221e515..0000000 +--- a/target/loongarch/insn_trans/trans_branch.c.inc ++++ /dev/null +@@ -1,84 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-static bool trans_b(DisasContext *ctx, arg_b *a) +-{ +- gen_goto_tb(ctx, 0, ctx->base.pc_next + a->offs); +- ctx->base.is_jmp = DISAS_NORETURN; +- return true; +-} +- +-static bool trans_bl(DisasContext *ctx, arg_bl *a) +-{ +- tcg_gen_movi_tl(cpu_gpr[1], make_address_pc(ctx, ctx->base.pc_next + 4)); +- gen_goto_tb(ctx, 0, ctx->base.pc_next + a->offs); +- ctx->base.is_jmp = DISAS_NORETURN; +- return true; +-} +- +-static bool trans_jirl(DisasContext *ctx, arg_jirl *a) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- +- TCGv addr = make_address_i(ctx, src1, a->imm); +- tcg_gen_mov_tl(cpu_pc, addr); +- tcg_gen_movi_tl(dest, make_address_pc(ctx, ctx->base.pc_next + 4)); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- tcg_gen_lookup_and_goto_ptr(); +- ctx->base.is_jmp = DISAS_NORETURN; +- return true; +-} +- +-static void gen_bc(DisasContext *ctx, TCGv src1, TCGv src2, +- target_long offs, TCGCond cond) +-{ +- TCGLabel *l = gen_new_label(); +- tcg_gen_brcond_tl(cond, src1, src2, l); +- gen_goto_tb(ctx, 1, ctx->base.pc_next + 4); +- gen_set_label(l); +- gen_goto_tb(ctx, 0, ctx->base.pc_next + offs); +- ctx->base.is_jmp = DISAS_NORETURN; +-} +- +-static bool gen_rr_bc(DisasContext *ctx, arg_rr_offs *a, TCGCond cond) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rd, EXT_NONE); +- +- gen_bc(ctx, src1, src2, a->offs, cond); +- return true; +-} +- +-static bool gen_rz_bc(DisasContext *ctx, arg_r_offs *a, TCGCond cond) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = tcg_constant_tl(0); +- +- gen_bc(ctx, src1, src2, a->offs, cond); +- return true; +-} +- +-static bool gen_cz_bc(DisasContext *ctx, arg_c_offs *a, TCGCond cond) +-{ +- TCGv src1 = tcg_temp_new(); +- TCGv src2 = tcg_constant_tl(0); +- +- tcg_gen_ld8u_tl(src1, tcg_env, +- offsetof(CPULoongArchState, cf[a->cj])); +- gen_bc(ctx, src1, src2, a->offs, cond); +- return true; +-} +- +-TRANS(beq, ALL, gen_rr_bc, TCG_COND_EQ) +-TRANS(bne, ALL, gen_rr_bc, TCG_COND_NE) +-TRANS(blt, ALL, gen_rr_bc, TCG_COND_LT) +-TRANS(bge, ALL, gen_rr_bc, TCG_COND_GE) +-TRANS(bltu, ALL, gen_rr_bc, TCG_COND_LTU) +-TRANS(bgeu, ALL, gen_rr_bc, TCG_COND_GEU) +-TRANS(beqz, ALL, gen_rz_bc, TCG_COND_EQ) +-TRANS(bnez, ALL, gen_rz_bc, TCG_COND_NE) +-TRANS(bceqz, 64, gen_cz_bc, TCG_COND_EQ) +-TRANS(bcnez, 64, gen_cz_bc, TCG_COND_NE) +diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc +deleted file mode 100644 +index cfa361f..0000000 +--- a/target/loongarch/insn_trans/trans_extra.c.inc ++++ /dev/null +@@ -1,107 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-static bool trans_break(DisasContext *ctx, arg_break *a) +-{ +- generate_exception(ctx, EXCCODE_BRK); +- return true; +-} +- +-static bool trans_syscall(DisasContext *ctx, arg_syscall *a) +-{ +- generate_exception(ctx, EXCCODE_SYS); +- return true; +-} +- +-static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d * a) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- +- if (!avail_64(ctx)) { +- return false; +- } +- +- gen_helper_asrtle_d(tcg_env, src1, src2); +- return true; +-} +- +-static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- +- if (!avail_64(ctx)) { +- return false; +- } +- +- gen_helper_asrtgt_d(tcg_env, src1, src2); +- return true; +-} +- +-static bool gen_rdtime(DisasContext *ctx, arg_rr *a, +- bool word, bool high) +-{ +- TCGv dst1 = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv dst2 = gpr_dst(ctx, a->rj, EXT_NONE); +- +- translator_io_start(&ctx->base); +- gen_helper_rdtime_d(dst1, tcg_env); +- if (word) { +- tcg_gen_sextract_tl(dst1, dst1, high ? 32 : 0, 32); +- } +- tcg_gen_ld_i64(dst2, tcg_env, offsetof(CPULoongArchState, CSR_TID)); +- +- return true; +-} +- +-static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a) +-{ +- return gen_rdtime(ctx, a, 1, 0); +-} +- +-static bool trans_rdtimeh_w(DisasContext *ctx, arg_rdtimeh_w *a) +-{ +- return gen_rdtime(ctx, a, 1, 1); +-} +- +-static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) +-{ +- return gen_rdtime(ctx, a, 0, 0); +-} +- +-static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- +- gen_helper_cpucfg(dest, tcg_env, src1); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static bool gen_crc(DisasContext *ctx, arg_rrr *a, +- void (*func)(TCGv, TCGv, TCGv, TCGv), +- TCGv tsz) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_SIGN); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- +- func(dest, src2, src1, tsz); +- gen_set_gpr(a->rd, dest, EXT_SIGN); +- +- return true; +-} +- +-TRANS(crc_w_b_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(1)) +-TRANS(crc_w_h_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(2)) +-TRANS(crc_w_w_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(4)) +-TRANS(crc_w_d_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(8)) +-TRANS(crcc_w_b_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(1)) +-TRANS(crcc_w_h_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(2)) +-TRANS(crcc_w_w_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(4)) +-TRANS(crcc_w_d_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(8)) +diff --git a/target/loongarch/insn_trans/trans_farith.c.inc b/target/loongarch/insn_trans/trans_farith.c.inc +deleted file mode 100644 +index f4a0dea..0000000 +--- a/target/loongarch/insn_trans/trans_farith.c.inc ++++ /dev/null +@@ -1,207 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-#ifndef CONFIG_USER_ONLY +-#define CHECK_FPE do { \ +- if ((ctx->base.tb->flags & HW_FLAGS_EUEN_FPE) == 0) { \ +- generate_exception(ctx, EXCCODE_FPD); \ +- return true; \ +- } \ +-} while (0) +-#else +-#define CHECK_FPE +-#endif +- +-static bool gen_fff(DisasContext *ctx, arg_fff *a, +- void (*func)(TCGv, TCGv_env, TCGv, TCGv)) +-{ +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src1 = get_fpr(ctx, a->fj); +- TCGv src2 = get_fpr(ctx, a->fk); +- +- CHECK_FPE; +- +- func(dest, tcg_env, src1, src2); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool gen_ff(DisasContext *ctx, arg_ff *a, +- void (*func)(TCGv, TCGv_env, TCGv)) +-{ +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src = get_fpr(ctx, a->fj); +- +- CHECK_FPE; +- +- func(dest, tcg_env, src); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool gen_muladd(DisasContext *ctx, arg_ffff *a, +- void (*func)(TCGv, TCGv_env, TCGv, TCGv, TCGv, TCGv_i32), +- int flag) +-{ +- TCGv_i32 tflag = tcg_constant_i32(flag); +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src1 = get_fpr(ctx, a->fj); +- TCGv src2 = get_fpr(ctx, a->fk); +- TCGv src3 = get_fpr(ctx, a->fa); +- +- CHECK_FPE; +- +- func(dest, tcg_env, src1, src2, src3, tflag); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool trans_fcopysign_s(DisasContext *ctx, arg_fcopysign_s *a) +-{ +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src1 = get_fpr(ctx, a->fk); +- TCGv src2 = get_fpr(ctx, a->fj); +- +- if (!avail_FP_SP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- tcg_gen_deposit_i64(dest, src1, src2, 0, 31); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool trans_fcopysign_d(DisasContext *ctx, arg_fcopysign_d *a) +-{ +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src1 = get_fpr(ctx, a->fk); +- TCGv src2 = get_fpr(ctx, a->fj); +- +- if (!avail_FP_DP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- tcg_gen_deposit_i64(dest, src1, src2, 0, 63); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool trans_fabs_s(DisasContext *ctx, arg_fabs_s *a) +-{ +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src = get_fpr(ctx, a->fj); +- +- if (!avail_FP_SP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- tcg_gen_andi_i64(dest, src, MAKE_64BIT_MASK(0, 31)); +- gen_nanbox_s(dest, dest); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool trans_fabs_d(DisasContext *ctx, arg_fabs_d *a) +-{ +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src = get_fpr(ctx, a->fj); +- +- if (!avail_FP_DP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- tcg_gen_andi_i64(dest, src, MAKE_64BIT_MASK(0, 63)); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool trans_fneg_s(DisasContext *ctx, arg_fneg_s *a) +-{ +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src = get_fpr(ctx, a->fj); +- +- if (!avail_FP_SP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- tcg_gen_xori_i64(dest, src, 0x80000000); +- gen_nanbox_s(dest, dest); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) +-{ +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src = get_fpr(ctx, a->fj); +- +- if (!avail_FP_DP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- tcg_gen_xori_i64(dest, src, 0x8000000000000000LL); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-TRANS(fadd_s, FP_SP, gen_fff, gen_helper_fadd_s) +-TRANS(fadd_d, FP_DP, gen_fff, gen_helper_fadd_d) +-TRANS(fsub_s, FP_SP, gen_fff, gen_helper_fsub_s) +-TRANS(fsub_d, FP_DP, gen_fff, gen_helper_fsub_d) +-TRANS(fmul_s, FP_SP, gen_fff, gen_helper_fmul_s) +-TRANS(fmul_d, FP_DP, gen_fff, gen_helper_fmul_d) +-TRANS(fdiv_s, FP_SP, gen_fff, gen_helper_fdiv_s) +-TRANS(fdiv_d, FP_DP, gen_fff, gen_helper_fdiv_d) +-TRANS(fmax_s, FP_SP, gen_fff, gen_helper_fmax_s) +-TRANS(fmax_d, FP_DP, gen_fff, gen_helper_fmax_d) +-TRANS(fmin_s, FP_SP, gen_fff, gen_helper_fmin_s) +-TRANS(fmin_d, FP_DP, gen_fff, gen_helper_fmin_d) +-TRANS(fmaxa_s, FP_SP, gen_fff, gen_helper_fmaxa_s) +-TRANS(fmaxa_d, FP_DP, gen_fff, gen_helper_fmaxa_d) +-TRANS(fmina_s, FP_SP, gen_fff, gen_helper_fmina_s) +-TRANS(fmina_d, FP_DP, gen_fff, gen_helper_fmina_d) +-TRANS(fscaleb_s, FP_SP, gen_fff, gen_helper_fscaleb_s) +-TRANS(fscaleb_d, FP_DP, gen_fff, gen_helper_fscaleb_d) +-TRANS(fsqrt_s, FP_SP, gen_ff, gen_helper_fsqrt_s) +-TRANS(fsqrt_d, FP_DP, gen_ff, gen_helper_fsqrt_d) +-TRANS(frecip_s, FP_SP, gen_ff, gen_helper_frecip_s) +-TRANS(frecip_d, FP_DP, gen_ff, gen_helper_frecip_d) +-TRANS(frsqrt_s, FP_SP, gen_ff, gen_helper_frsqrt_s) +-TRANS(frsqrt_d, FP_DP, gen_ff, gen_helper_frsqrt_d) +-TRANS(flogb_s, FP_SP, gen_ff, gen_helper_flogb_s) +-TRANS(flogb_d, FP_DP, gen_ff, gen_helper_flogb_d) +-TRANS(fclass_s, FP_SP, gen_ff, gen_helper_fclass_s) +-TRANS(fclass_d, FP_DP, gen_ff, gen_helper_fclass_d) +-TRANS(fmadd_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, 0) +-TRANS(fmadd_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, 0) +-TRANS(fmsub_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c) +-TRANS(fmsub_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c) +-TRANS(fnmadd_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_result) +-TRANS(fnmadd_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_result) +-TRANS(fnmsub_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, +- float_muladd_negate_c | float_muladd_negate_result) +-TRANS(fnmsub_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, +- float_muladd_negate_c | float_muladd_negate_result) +diff --git a/target/loongarch/insn_trans/trans_fcmp.c.inc b/target/loongarch/insn_trans/trans_fcmp.c.inc +deleted file mode 100644 +index 3babf69..0000000 +--- a/target/loongarch/insn_trans/trans_fcmp.c.inc ++++ /dev/null +@@ -1,72 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-/* bit0(signaling/quiet) bit1(lt) bit2(eq) bit3(un) bit4(neq) */ +-static uint32_t get_fcmp_flags(int cond) +-{ +- uint32_t flags = 0; +- +- if (cond & 0x1) { +- flags |= FCMP_LT; +- } +- if (cond & 0x2) { +- flags |= FCMP_EQ; +- } +- if (cond & 0x4) { +- flags |= FCMP_UN; +- } +- if (cond & 0x8) { +- flags |= FCMP_GT | FCMP_LT; +- } +- return flags; +-} +- +-static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) +-{ +- TCGv var, src1, src2; +- uint32_t flags; +- void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); +- +- if (!avail_FP_SP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- var = tcg_temp_new(); +- src1 = get_fpr(ctx, a->fj); +- src2 = get_fpr(ctx, a->fk); +- fn = (a->fcond & 1 ? gen_helper_fcmp_s_s : gen_helper_fcmp_c_s); +- flags = get_fcmp_flags(a->fcond >> 1); +- +- fn(var, tcg_env, src1, src2, tcg_constant_i32(flags)); +- +- tcg_gen_st8_tl(var, tcg_env, offsetof(CPULoongArchState, cf[a->cd])); +- return true; +-} +- +-static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) +-{ +- TCGv var, src1, src2; +- uint32_t flags; +- void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); +- +- if (!avail_FP_DP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- var = tcg_temp_new(); +- src1 = get_fpr(ctx, a->fj); +- src2 = get_fpr(ctx, a->fk); +- fn = (a->fcond & 1 ? gen_helper_fcmp_s_d : gen_helper_fcmp_c_d); +- flags = get_fcmp_flags(a->fcond >> 1); +- +- fn(var, tcg_env, src1, src2, tcg_constant_i32(flags)); +- +- tcg_gen_st8_tl(var, tcg_env, offsetof(CPULoongArchState, cf[a->cd])); +- return true; +-} +diff --git a/target/loongarch/insn_trans/trans_fcnv.c.inc b/target/loongarch/insn_trans/trans_fcnv.c.inc +deleted file mode 100644 +index 833c059..0000000 +--- a/target/loongarch/insn_trans/trans_fcnv.c.inc ++++ /dev/null +@@ -1,33 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-TRANS(fcvt_s_d, FP_DP, gen_ff, gen_helper_fcvt_s_d) +-TRANS(fcvt_d_s, FP_DP, gen_ff, gen_helper_fcvt_d_s) +-TRANS(ftintrm_w_s, FP_SP, gen_ff, gen_helper_ftintrm_w_s) +-TRANS(ftintrm_w_d, FP_DP, gen_ff, gen_helper_ftintrm_w_d) +-TRANS(ftintrm_l_s, FP_SP, gen_ff, gen_helper_ftintrm_l_s) +-TRANS(ftintrm_l_d, FP_DP, gen_ff, gen_helper_ftintrm_l_d) +-TRANS(ftintrp_w_s, FP_SP, gen_ff, gen_helper_ftintrp_w_s) +-TRANS(ftintrp_w_d, FP_DP, gen_ff, gen_helper_ftintrp_w_d) +-TRANS(ftintrp_l_s, FP_SP, gen_ff, gen_helper_ftintrp_l_s) +-TRANS(ftintrp_l_d, FP_DP, gen_ff, gen_helper_ftintrp_l_d) +-TRANS(ftintrz_w_s, FP_SP, gen_ff, gen_helper_ftintrz_w_s) +-TRANS(ftintrz_w_d, FP_DP, gen_ff, gen_helper_ftintrz_w_d) +-TRANS(ftintrz_l_s, FP_SP, gen_ff, gen_helper_ftintrz_l_s) +-TRANS(ftintrz_l_d, FP_DP, gen_ff, gen_helper_ftintrz_l_d) +-TRANS(ftintrne_w_s, FP_SP, gen_ff, gen_helper_ftintrne_w_s) +-TRANS(ftintrne_w_d, FP_DP, gen_ff, gen_helper_ftintrne_w_d) +-TRANS(ftintrne_l_s, FP_SP, gen_ff, gen_helper_ftintrne_l_s) +-TRANS(ftintrne_l_d, FP_DP, gen_ff, gen_helper_ftintrne_l_d) +-TRANS(ftint_w_s, FP_SP, gen_ff, gen_helper_ftint_w_s) +-TRANS(ftint_w_d, FP_DP, gen_ff, gen_helper_ftint_w_d) +-TRANS(ftint_l_s, FP_SP, gen_ff, gen_helper_ftint_l_s) +-TRANS(ftint_l_d, FP_DP, gen_ff, gen_helper_ftint_l_d) +-TRANS(ffint_s_w, FP_SP, gen_ff, gen_helper_ffint_s_w) +-TRANS(ffint_s_l, FP_SP, gen_ff, gen_helper_ffint_s_l) +-TRANS(ffint_d_w, FP_DP, gen_ff, gen_helper_ffint_d_w) +-TRANS(ffint_d_l, FP_DP, gen_ff, gen_helper_ffint_d_l) +-TRANS(frint_s, FP_SP, gen_ff, gen_helper_frint_s) +-TRANS(frint_d, FP_DP, gen_ff, gen_helper_frint_d) +diff --git a/target/loongarch/insn_trans/trans_fmemory.c.inc b/target/loongarch/insn_trans/trans_fmemory.c.inc +deleted file mode 100644 +index 13452bc..0000000 +--- a/target/loongarch/insn_trans/trans_fmemory.c.inc ++++ /dev/null +@@ -1,158 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-static void maybe_nanbox_load(TCGv freg, MemOp mop) +-{ +- if ((mop & MO_SIZE) == MO_32) { +- gen_nanbox_s(freg, freg); +- } +-} +- +-static bool gen_fload_i(DisasContext *ctx, arg_fr_i *a, MemOp mop) +-{ +- TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv dest = get_fpr(ctx, a->fd); +- +- CHECK_FPE; +- +- addr = make_address_i(ctx, addr, a->imm); +- +- tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); +- maybe_nanbox_load(dest, mop); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool gen_fstore_i(DisasContext *ctx, arg_fr_i *a, MemOp mop) +-{ +- TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src = get_fpr(ctx, a->fd); +- +- CHECK_FPE; +- +- addr = make_address_i(ctx, addr, a->imm); +- +- tcg_gen_qemu_st_tl(src, addr, ctx->mem_idx, mop); +- +- return true; +-} +- +-static bool gen_floadx(DisasContext *ctx, arg_frr *a, MemOp mop) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv addr; +- +- CHECK_FPE; +- +- addr = make_address_x(ctx, src1, src2); +- tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); +- maybe_nanbox_load(dest, mop); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool gen_fstorex(DisasContext *ctx, arg_frr *a, MemOp mop) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- TCGv src3 = get_fpr(ctx, a->fd); +- TCGv addr; +- +- CHECK_FPE; +- +- addr = make_address_x(ctx, src1, src2); +- tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); +- +- return true; +-} +- +-static bool gen_fload_gt(DisasContext *ctx, arg_frr *a, MemOp mop) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv addr; +- +- CHECK_FPE; +- +- gen_helper_asrtgt_d(tcg_env, src1, src2); +- addr = make_address_x(ctx, src1, src2); +- tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); +- maybe_nanbox_load(dest, mop); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool gen_fstore_gt(DisasContext *ctx, arg_frr *a, MemOp mop) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- TCGv src3 = get_fpr(ctx, a->fd); +- TCGv addr; +- +- CHECK_FPE; +- +- gen_helper_asrtgt_d(tcg_env, src1, src2); +- addr = make_address_x(ctx, src1, src2); +- tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); +- +- return true; +-} +- +-static bool gen_fload_le(DisasContext *ctx, arg_frr *a, MemOp mop) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv addr; +- +- CHECK_FPE; +- +- gen_helper_asrtle_d(tcg_env, src1, src2); +- addr = make_address_x(ctx, src1, src2); +- tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); +- maybe_nanbox_load(dest, mop); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool gen_fstore_le(DisasContext *ctx, arg_frr *a, MemOp mop) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- TCGv src3 = get_fpr(ctx, a->fd); +- TCGv addr; +- +- CHECK_FPE; +- +- gen_helper_asrtle_d(tcg_env, src1, src2); +- addr = make_address_x(ctx, src1, src2); +- tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); +- +- return true; +-} +- +-TRANS(fld_s, FP_SP, gen_fload_i, MO_TEUL) +-TRANS(fst_s, FP_SP, gen_fstore_i, MO_TEUL) +-TRANS(fld_d, FP_DP, gen_fload_i, MO_TEUQ) +-TRANS(fst_d, FP_DP, gen_fstore_i, MO_TEUQ) +-TRANS(fldx_s, FP_SP, gen_floadx, MO_TEUL) +-TRANS(fldx_d, FP_DP, gen_floadx, MO_TEUQ) +-TRANS(fstx_s, FP_SP, gen_fstorex, MO_TEUL) +-TRANS(fstx_d, FP_DP, gen_fstorex, MO_TEUQ) +-TRANS(fldgt_s, FP_SP, gen_fload_gt, MO_TEUL) +-TRANS(fldgt_d, FP_DP, gen_fload_gt, MO_TEUQ) +-TRANS(fldle_s, FP_SP, gen_fload_le, MO_TEUL) +-TRANS(fldle_d, FP_DP, gen_fload_le, MO_TEUQ) +-TRANS(fstgt_s, FP_SP, gen_fstore_gt, MO_TEUL) +-TRANS(fstgt_d, FP_DP, gen_fstore_gt, MO_TEUQ) +-TRANS(fstle_s, FP_SP, gen_fstore_le, MO_TEUL) +-TRANS(fstle_d, FP_DP, gen_fstore_le, MO_TEUQ) +diff --git a/target/loongarch/insn_trans/trans_fmov.c.inc b/target/loongarch/insn_trans/trans_fmov.c.inc +deleted file mode 100644 +index 5cbd9d3..0000000 +--- a/target/loongarch/insn_trans/trans_fmov.c.inc ++++ /dev/null +@@ -1,224 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-static const uint32_t fcsr_mask[4] = { +- UINT32_MAX, FCSR0_M1, FCSR0_M2, FCSR0_M3 +-}; +- +-static bool trans_fsel(DisasContext *ctx, arg_fsel *a) +-{ +- TCGv zero = tcg_constant_tl(0); +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src1 = get_fpr(ctx, a->fj); +- TCGv src2 = get_fpr(ctx, a->fk); +- TCGv cond; +- +- if (!avail_FP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- cond = tcg_temp_new(); +- tcg_gen_ld8u_tl(cond, tcg_env, offsetof(CPULoongArchState, cf[a->ca])); +- tcg_gen_movcond_tl(TCG_COND_EQ, dest, cond, zero, src1, src2); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool gen_f2f(DisasContext *ctx, arg_ff *a, +- void (*func)(TCGv, TCGv), bool nanbox) +-{ +- TCGv dest = get_fpr(ctx, a->fd); +- TCGv src = get_fpr(ctx, a->fj); +- +- CHECK_FPE; +- +- func(dest, src); +- if (nanbox) { +- gen_nanbox_s(dest, dest); +- } +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool gen_r2f(DisasContext *ctx, arg_fr *a, +- void (*func)(TCGv, TCGv)) +-{ +- TCGv src = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv dest = get_fpr(ctx, a->fd); +- +- if (!avail_FP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- func(dest, src); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool gen_f2r(DisasContext *ctx, arg_rf *a, +- void (*func)(TCGv, TCGv)) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src = get_fpr(ctx, a->fj); +- +- if (!avail_FP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- func(dest, src); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) +-{ +- uint32_t mask = fcsr_mask[a->fcsrd]; +- TCGv Rj = gpr_src(ctx, a->rj, EXT_NONE); +- +- if (!avail_FP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- if (mask == UINT32_MAX) { +- tcg_gen_st32_i64(Rj, tcg_env, offsetof(CPULoongArchState, fcsr0)); +- } else { +- TCGv_i32 fcsr0 = tcg_temp_new_i32(); +- TCGv_i32 temp = tcg_temp_new_i32(); +- +- tcg_gen_ld_i32(fcsr0, tcg_env, offsetof(CPULoongArchState, fcsr0)); +- tcg_gen_extrl_i64_i32(temp, Rj); +- tcg_gen_andi_i32(temp, temp, mask); +- tcg_gen_andi_i32(fcsr0, fcsr0, ~mask); +- tcg_gen_or_i32(fcsr0, fcsr0, temp); +- tcg_gen_st_i32(fcsr0, tcg_env, offsetof(CPULoongArchState, fcsr0)); +- } +- +- /* +- * Install the new rounding mode to fpu_status, if changed. +- * Note that FCSR3 is exactly the rounding mode field. +- */ +- if (mask & FCSR0_M3) { +- gen_helper_set_rounding_mode(tcg_env); +- } +- return true; +-} +- +-static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- +- if (!avail_FP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- tcg_gen_ld32u_i64(dest, tcg_env, offsetof(CPULoongArchState, fcsr0)); +- tcg_gen_andi_i64(dest, dest, fcsr_mask[a->fcsrs]); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static void gen_movgr2fr_w(TCGv dest, TCGv src) +-{ +- tcg_gen_deposit_i64(dest, dest, src, 0, 32); +-} +- +-static void gen_movgr2frh_w(TCGv dest, TCGv src) +-{ +- tcg_gen_deposit_i64(dest, dest, src, 32, 32); +-} +- +-static void gen_movfrh2gr_s(TCGv dest, TCGv src) +-{ +- tcg_gen_sextract_tl(dest, src, 32, 32); +-} +- +-static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) +-{ +- TCGv t0; +- TCGv src = get_fpr(ctx, a->fj); +- +- if (!avail_FP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- t0 = tcg_temp_new(); +- tcg_gen_andi_tl(t0, src, 0x1); +- tcg_gen_st8_tl(t0, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); +- +- return true; +-} +- +-static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) +-{ +- TCGv dest = get_fpr(ctx, a->fd); +- +- if (!avail_FP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- tcg_gen_ld8u_tl(dest, tcg_env, +- offsetof(CPULoongArchState, cf[a->cj & 0x7])); +- set_fpr(a->fd, dest); +- +- return true; +-} +- +-static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) +-{ +- TCGv t0; +- +- if (!avail_FP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- t0 = tcg_temp_new(); +- tcg_gen_andi_tl(t0, gpr_src(ctx, a->rj, EXT_NONE), 0x1); +- tcg_gen_st8_tl(t0, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); +- +- return true; +-} +- +-static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) +-{ +- if (!avail_FP(ctx)) { +- return false; +- } +- +- CHECK_FPE; +- +- tcg_gen_ld8u_tl(gpr_dst(ctx, a->rd, EXT_NONE), tcg_env, +- offsetof(CPULoongArchState, cf[a->cj & 0x7])); +- return true; +-} +- +-TRANS(fmov_s, FP_SP, gen_f2f, tcg_gen_mov_tl, true) +-TRANS(fmov_d, FP_DP, gen_f2f, tcg_gen_mov_tl, false) +-TRANS(movgr2fr_w, FP_SP, gen_r2f, gen_movgr2fr_w) +-TRANS(movgr2fr_d, 64, gen_r2f, tcg_gen_mov_tl) +-TRANS(movgr2frh_w, FP_DP, gen_r2f, gen_movgr2frh_w) +-TRANS(movfr2gr_s, FP_SP, gen_f2r, tcg_gen_ext32s_tl) +-TRANS(movfr2gr_d, 64, gen_f2r, tcg_gen_mov_tl) +-TRANS(movfrh2gr_s, FP_DP, gen_f2r, gen_movfrh2gr_s) +diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/insn_trans/trans_memory.c.inc +deleted file mode 100644 +index 42f4e74..0000000 +--- a/target/loongarch/insn_trans/trans_memory.c.inc ++++ /dev/null +@@ -1,194 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-static bool gen_load(DisasContext *ctx, arg_rr_i *a, MemOp mop) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); +- +- addr = make_address_i(ctx, addr, a->imm); +- +- tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- return true; +-} +- +-static bool gen_store(DisasContext *ctx, arg_rr_i *a, MemOp mop) +-{ +- TCGv data = gpr_src(ctx, a->rd, EXT_NONE); +- TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); +- +- addr = make_address_i(ctx, addr, a->imm); +- +- tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); +- return true; +-} +- +-static bool gen_loadx(DisasContext *ctx, arg_rrr *a, MemOp mop) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- TCGv addr = make_address_x(ctx, src1, src2); +- +- tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static bool gen_storex(DisasContext *ctx, arg_rrr *a, MemOp mop) +-{ +- TCGv data = gpr_src(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- TCGv addr = make_address_x(ctx, src1, src2); +- +- tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); +- +- return true; +-} +- +-static bool gen_load_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- +- gen_helper_asrtgt_d(tcg_env, src1, src2); +- src1 = make_address_i(ctx, src1, 0); +- tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static bool gen_load_le(DisasContext *ctx, arg_rrr *a, MemOp mop) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- +- gen_helper_asrtle_d(tcg_env, src1, src2); +- src1 = make_address_i(ctx, src1, 0); +- tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-static bool gen_store_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) +-{ +- TCGv data = gpr_src(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- +- gen_helper_asrtgt_d(tcg_env, src1, src2); +- src1 = make_address_i(ctx, src1, 0); +- tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); +- +- return true; +-} +- +-static bool gen_store_le(DisasContext *ctx, arg_rrr *a, MemOp mop) +-{ +- TCGv data = gpr_src(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- +- gen_helper_asrtle_d(tcg_env, src1, src2); +- src1 = make_address_i(ctx, src1, 0); +- tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); +- +- return true; +-} +- +-static bool trans_preld(DisasContext *ctx, arg_preld *a) +-{ +- return true; +-} +- +-static bool trans_preldx(DisasContext *ctx, arg_preldx * a) +-{ +- return true; +-} +- +-static bool trans_dbar(DisasContext *ctx, arg_dbar * a) +-{ +- tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); +- return true; +-} +- +-static bool trans_ibar(DisasContext *ctx, arg_ibar *a) +-{ +- ctx->base.is_jmp = DISAS_STOP; +- return true; +-} +- +-static bool gen_ldptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); +- +- addr = make_address_i(ctx, addr, a->imm); +- +- tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- return true; +-} +- +-static bool gen_stptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) +-{ +- TCGv data = gpr_src(ctx, a->rd, EXT_NONE); +- TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); +- +- addr = make_address_i(ctx, addr, a->imm); +- +- tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); +- return true; +-} +- +-TRANS(ld_b, ALL, gen_load, MO_SB) +-TRANS(ld_h, ALL, gen_load, MO_TESW) +-TRANS(ld_w, ALL, gen_load, MO_TESL) +-TRANS(ld_d, 64, gen_load, MO_TEUQ) +-TRANS(st_b, ALL, gen_store, MO_UB) +-TRANS(st_h, ALL, gen_store, MO_TEUW) +-TRANS(st_w, ALL, gen_store, MO_TEUL) +-TRANS(st_d, 64, gen_store, MO_TEUQ) +-TRANS(ld_bu, ALL, gen_load, MO_UB) +-TRANS(ld_hu, ALL, gen_load, MO_TEUW) +-TRANS(ld_wu, 64, gen_load, MO_TEUL) +-TRANS(ldx_b, 64, gen_loadx, MO_SB) +-TRANS(ldx_h, 64, gen_loadx, MO_TESW) +-TRANS(ldx_w, 64, gen_loadx, MO_TESL) +-TRANS(ldx_d, 64, gen_loadx, MO_TEUQ) +-TRANS(stx_b, 64, gen_storex, MO_UB) +-TRANS(stx_h, 64, gen_storex, MO_TEUW) +-TRANS(stx_w, 64, gen_storex, MO_TEUL) +-TRANS(stx_d, 64, gen_storex, MO_TEUQ) +-TRANS(ldx_bu, 64, gen_loadx, MO_UB) +-TRANS(ldx_hu, 64, gen_loadx, MO_TEUW) +-TRANS(ldx_wu, 64, gen_loadx, MO_TEUL) +-TRANS(ldptr_w, 64, gen_ldptr, MO_TESL) +-TRANS(stptr_w, 64, gen_stptr, MO_TEUL) +-TRANS(ldptr_d, 64, gen_ldptr, MO_TEUQ) +-TRANS(stptr_d, 64, gen_stptr, MO_TEUQ) +-TRANS(ldgt_b, 64, gen_load_gt, MO_SB) +-TRANS(ldgt_h, 64, gen_load_gt, MO_TESW) +-TRANS(ldgt_w, 64, gen_load_gt, MO_TESL) +-TRANS(ldgt_d, 64, gen_load_gt, MO_TEUQ) +-TRANS(ldle_b, 64, gen_load_le, MO_SB) +-TRANS(ldle_h, 64, gen_load_le, MO_TESW) +-TRANS(ldle_w, 64, gen_load_le, MO_TESL) +-TRANS(ldle_d, 64, gen_load_le, MO_TEUQ) +-TRANS(stgt_b, 64, gen_store_gt, MO_UB) +-TRANS(stgt_h, 64, gen_store_gt, MO_TEUW) +-TRANS(stgt_w, 64, gen_store_gt, MO_TEUL) +-TRANS(stgt_d, 64, gen_store_gt, MO_TEUQ) +-TRANS(stle_b, 64, gen_store_le, MO_UB) +-TRANS(stle_h, 64, gen_store_le, MO_TEUW) +-TRANS(stle_w, 64, gen_store_le, MO_TEUL) +-TRANS(stle_d, 64, gen_store_le, MO_TEUQ) +diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc +deleted file mode 100644 +index 01d4572..0000000 +--- a/target/loongarch/insn_trans/trans_privileged.c.inc ++++ /dev/null +@@ -1,498 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- * +- * LoongArch translation routines for the privileged instructions. +- */ +- +-#include "cpu-csr.h" +- +-#ifdef CONFIG_USER_ONLY +- +-#define GEN_FALSE_TRANS(name) \ +-static bool trans_##name(DisasContext *ctx, arg_##name * a) \ +-{ \ +- return false; \ +-} +- +-GEN_FALSE_TRANS(csrrd) +-GEN_FALSE_TRANS(csrwr) +-GEN_FALSE_TRANS(csrxchg) +-GEN_FALSE_TRANS(iocsrrd_b) +-GEN_FALSE_TRANS(iocsrrd_h) +-GEN_FALSE_TRANS(iocsrrd_w) +-GEN_FALSE_TRANS(iocsrrd_d) +-GEN_FALSE_TRANS(iocsrwr_b) +-GEN_FALSE_TRANS(iocsrwr_h) +-GEN_FALSE_TRANS(iocsrwr_w) +-GEN_FALSE_TRANS(iocsrwr_d) +-GEN_FALSE_TRANS(tlbsrch) +-GEN_FALSE_TRANS(tlbrd) +-GEN_FALSE_TRANS(tlbwr) +-GEN_FALSE_TRANS(tlbfill) +-GEN_FALSE_TRANS(tlbclr) +-GEN_FALSE_TRANS(tlbflush) +-GEN_FALSE_TRANS(invtlb) +-GEN_FALSE_TRANS(cacop) +-GEN_FALSE_TRANS(ldpte) +-GEN_FALSE_TRANS(lddir) +-GEN_FALSE_TRANS(ertn) +-GEN_FALSE_TRANS(dbcl) +-GEN_FALSE_TRANS(idle) +- +-#else +- +-typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env); +-typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src); +- +-typedef struct { +- int offset; +- int flags; +- GenCSRRead readfn; +- GenCSRWrite writefn; +-} CSRInfo; +- +-enum { +- CSRFL_READONLY = (1 << 0), +- CSRFL_EXITTB = (1 << 1), +- CSRFL_IO = (1 << 2), +-}; +- +-#define CSR_OFF_FUNCS(NAME, FL, RD, WR) \ +- [LOONGARCH_CSR_##NAME] = { \ +- .offset = offsetof(CPULoongArchState, CSR_##NAME), \ +- .flags = FL, .readfn = RD, .writefn = WR \ +- } +- +-#define CSR_OFF_ARRAY(NAME, N) \ +- [LOONGARCH_CSR_##NAME(N)] = { \ +- .offset = offsetof(CPULoongArchState, CSR_##NAME[N]), \ +- .flags = 0, .readfn = NULL, .writefn = NULL \ +- } +- +-#define CSR_OFF_FLAGS(NAME, FL) \ +- CSR_OFF_FUNCS(NAME, FL, NULL, NULL) +- +-#define CSR_OFF(NAME) \ +- CSR_OFF_FLAGS(NAME, 0) +- +-static const CSRInfo csr_info[] = { +- CSR_OFF_FLAGS(CRMD, CSRFL_EXITTB), +- CSR_OFF(PRMD), +- CSR_OFF_FLAGS(EUEN, CSRFL_EXITTB), +- CSR_OFF_FLAGS(MISC, CSRFL_READONLY), +- CSR_OFF(ECFG), +- CSR_OFF_FUNCS(ESTAT, CSRFL_EXITTB, NULL, gen_helper_csrwr_estat), +- CSR_OFF(ERA), +- CSR_OFF(BADV), +- CSR_OFF_FLAGS(BADI, CSRFL_READONLY), +- CSR_OFF(EENTRY), +- CSR_OFF(TLBIDX), +- CSR_OFF(TLBEHI), +- CSR_OFF(TLBELO0), +- CSR_OFF(TLBELO1), +- CSR_OFF_FUNCS(ASID, CSRFL_EXITTB, NULL, gen_helper_csrwr_asid), +- CSR_OFF(PGDL), +- CSR_OFF(PGDH), +- CSR_OFF_FUNCS(PGD, CSRFL_READONLY, gen_helper_csrrd_pgd, NULL), +- CSR_OFF(PWCL), +- CSR_OFF(PWCH), +- CSR_OFF(STLBPS), +- CSR_OFF(RVACFG), +- CSR_OFF_FUNCS(CPUID, CSRFL_READONLY, gen_helper_csrrd_cpuid, NULL), +- CSR_OFF_FLAGS(PRCFG1, CSRFL_READONLY), +- CSR_OFF_FLAGS(PRCFG2, CSRFL_READONLY), +- CSR_OFF_FLAGS(PRCFG3, CSRFL_READONLY), +- CSR_OFF_ARRAY(SAVE, 0), +- CSR_OFF_ARRAY(SAVE, 1), +- CSR_OFF_ARRAY(SAVE, 2), +- CSR_OFF_ARRAY(SAVE, 3), +- CSR_OFF_ARRAY(SAVE, 4), +- CSR_OFF_ARRAY(SAVE, 5), +- CSR_OFF_ARRAY(SAVE, 6), +- CSR_OFF_ARRAY(SAVE, 7), +- CSR_OFF_ARRAY(SAVE, 8), +- CSR_OFF_ARRAY(SAVE, 9), +- CSR_OFF_ARRAY(SAVE, 10), +- CSR_OFF_ARRAY(SAVE, 11), +- CSR_OFF_ARRAY(SAVE, 12), +- CSR_OFF_ARRAY(SAVE, 13), +- CSR_OFF_ARRAY(SAVE, 14), +- CSR_OFF_ARRAY(SAVE, 15), +- CSR_OFF(TID), +- CSR_OFF_FUNCS(TCFG, CSRFL_IO, NULL, gen_helper_csrwr_tcfg), +- CSR_OFF_FUNCS(TVAL, CSRFL_READONLY | CSRFL_IO, gen_helper_csrrd_tval, NULL), +- CSR_OFF(CNTC), +- CSR_OFF_FUNCS(TICLR, CSRFL_IO, NULL, gen_helper_csrwr_ticlr), +- CSR_OFF(LLBCTL), +- CSR_OFF(IMPCTL1), +- CSR_OFF(IMPCTL2), +- CSR_OFF(TLBRENTRY), +- CSR_OFF(TLBRBADV), +- CSR_OFF(TLBRERA), +- CSR_OFF(TLBRSAVE), +- CSR_OFF(TLBRELO0), +- CSR_OFF(TLBRELO1), +- CSR_OFF(TLBREHI), +- CSR_OFF(TLBRPRMD), +- CSR_OFF(MERRCTL), +- CSR_OFF(MERRINFO1), +- CSR_OFF(MERRINFO2), +- CSR_OFF(MERRENTRY), +- CSR_OFF(MERRERA), +- CSR_OFF(MERRSAVE), +- CSR_OFF(CTAG), +- CSR_OFF_ARRAY(DMW, 0), +- CSR_OFF_ARRAY(DMW, 1), +- CSR_OFF_ARRAY(DMW, 2), +- CSR_OFF_ARRAY(DMW, 3), +- CSR_OFF(DBG), +- CSR_OFF(DERA), +- CSR_OFF(DSAVE), +-}; +- +-static bool check_plv(DisasContext *ctx) +-{ +- if (ctx->plv == MMU_PLV_USER) { +- generate_exception(ctx, EXCCODE_IPE); +- return true; +- } +- return false; +-} +- +-static const CSRInfo *get_csr(unsigned csr_num) +-{ +- const CSRInfo *csr; +- +- if (csr_num >= ARRAY_SIZE(csr_info)) { +- return NULL; +- } +- csr = &csr_info[csr_num]; +- if (csr->offset == 0) { +- return NULL; +- } +- return csr; +-} +- +-static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write) +-{ +- if ((csr->flags & CSRFL_READONLY) && write) { +- return false; +- } +- if ((csr->flags & CSRFL_IO) && translator_io_start(&ctx->base)) { +- ctx->base.is_jmp = DISAS_EXIT_UPDATE; +- } else if ((csr->flags & CSRFL_EXITTB) && write) { +- ctx->base.is_jmp = DISAS_EXIT_UPDATE; +- } +- return true; +-} +- +-static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a) +-{ +- TCGv dest; +- const CSRInfo *csr; +- +- if (check_plv(ctx)) { +- return false; +- } +- csr = get_csr(a->csr); +- if (csr == NULL) { +- /* CSR is undefined: read as 0. */ +- dest = tcg_constant_tl(0); +- } else { +- check_csr_flags(ctx, csr, false); +- dest = gpr_dst(ctx, a->rd, EXT_NONE); +- if (csr->readfn) { +- csr->readfn(dest, tcg_env); +- } else { +- tcg_gen_ld_tl(dest, tcg_env, csr->offset); +- } +- } +- gen_set_gpr(a->rd, dest, EXT_NONE); +- return true; +-} +- +-static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a) +-{ +- TCGv dest, src1; +- const CSRInfo *csr; +- +- if (check_plv(ctx)) { +- return false; +- } +- csr = get_csr(a->csr); +- if (csr == NULL) { +- /* CSR is undefined: write ignored, read old_value as 0. */ +- gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); +- return true; +- } +- if (!check_csr_flags(ctx, csr, true)) { +- /* CSR is readonly: trap. */ +- return false; +- } +- src1 = gpr_src(ctx, a->rd, EXT_NONE); +- if (csr->writefn) { +- dest = gpr_dst(ctx, a->rd, EXT_NONE); +- csr->writefn(dest, tcg_env, src1); +- } else { +- dest = tcg_temp_new(); +- tcg_gen_ld_tl(dest, tcg_env, csr->offset); +- tcg_gen_st_tl(src1, tcg_env, csr->offset); +- } +- gen_set_gpr(a->rd, dest, EXT_NONE); +- return true; +-} +- +-static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) +-{ +- TCGv src1, mask, oldv, newv, temp; +- const CSRInfo *csr; +- +- if (check_plv(ctx)) { +- return false; +- } +- csr = get_csr(a->csr); +- if (csr == NULL) { +- /* CSR is undefined: write ignored, read old_value as 0. */ +- gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); +- return true; +- } +- +- if (!check_csr_flags(ctx, csr, true)) { +- /* CSR is readonly: trap. */ +- return false; +- } +- +- /* So far only readonly csrs have readfn. */ +- assert(csr->readfn == NULL); +- +- src1 = gpr_src(ctx, a->rd, EXT_NONE); +- mask = gpr_src(ctx, a->rj, EXT_NONE); +- oldv = tcg_temp_new(); +- newv = tcg_temp_new(); +- temp = tcg_temp_new(); +- +- tcg_gen_ld_tl(oldv, tcg_env, csr->offset); +- tcg_gen_and_tl(newv, src1, mask); +- tcg_gen_andc_tl(temp, oldv, mask); +- tcg_gen_or_tl(newv, newv, temp); +- +- if (csr->writefn) { +- csr->writefn(oldv, tcg_env, newv); +- } else { +- tcg_gen_st_tl(newv, tcg_env, csr->offset); +- } +- gen_set_gpr(a->rd, oldv, EXT_NONE); +- return true; +-} +- +-static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a, +- void (*func)(TCGv, TCGv_ptr, TCGv)) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- +- if (check_plv(ctx)) { +- return false; +- } +- func(dest, tcg_env, src1); +- return true; +-} +- +-static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a, +- void (*func)(TCGv_ptr, TCGv, TCGv)) +-{ +- TCGv val = gpr_src(ctx, a->rd, EXT_NONE); +- TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); +- +- if (check_plv(ctx)) { +- return false; +- } +- func(tcg_env, addr, val); +- return true; +-} +- +-TRANS(iocsrrd_b, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_b) +-TRANS(iocsrrd_h, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_h) +-TRANS(iocsrrd_w, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_w) +-TRANS(iocsrrd_d, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_d) +-TRANS(iocsrwr_b, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_b) +-TRANS(iocsrwr_h, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_h) +-TRANS(iocsrwr_w, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_w) +-TRANS(iocsrwr_d, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_d) +- +-static void check_mmu_idx(DisasContext *ctx) +-{ +- if (ctx->mem_idx != MMU_IDX_DA) { +- tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4); +- ctx->base.is_jmp = DISAS_EXIT; +- } +-} +- +-static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a) +-{ +- if (check_plv(ctx)) { +- return false; +- } +- gen_helper_tlbsrch(tcg_env); +- return true; +-} +- +-static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a) +-{ +- if (check_plv(ctx)) { +- return false; +- } +- gen_helper_tlbrd(tcg_env); +- return true; +-} +- +-static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a) +-{ +- if (check_plv(ctx)) { +- return false; +- } +- gen_helper_tlbwr(tcg_env); +- check_mmu_idx(ctx); +- return true; +-} +- +-static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a) +-{ +- if (check_plv(ctx)) { +- return false; +- } +- gen_helper_tlbfill(tcg_env); +- check_mmu_idx(ctx); +- return true; +-} +- +-static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a) +-{ +- if (check_plv(ctx)) { +- return false; +- } +- gen_helper_tlbclr(tcg_env); +- check_mmu_idx(ctx); +- return true; +-} +- +-static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a) +-{ +- if (check_plv(ctx)) { +- return false; +- } +- gen_helper_tlbflush(tcg_env); +- check_mmu_idx(ctx); +- return true; +-} +- +-static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) +-{ +- TCGv rj = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv rk = gpr_src(ctx, a->rk, EXT_NONE); +- +- if (check_plv(ctx)) { +- return false; +- } +- +- switch (a->imm) { +- case 0: +- case 1: +- gen_helper_invtlb_all(tcg_env); +- break; +- case 2: +- gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(1)); +- break; +- case 3: +- gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(0)); +- break; +- case 4: +- gen_helper_invtlb_all_asid(tcg_env, rj); +- break; +- case 5: +- gen_helper_invtlb_page_asid(tcg_env, rj, rk); +- break; +- case 6: +- gen_helper_invtlb_page_asid_or_g(tcg_env, rj, rk); +- break; +- default: +- return false; +- } +- ctx->base.is_jmp = DISAS_STOP; +- return true; +-} +- +-static bool trans_cacop(DisasContext *ctx, arg_cacop *a) +-{ +- /* Treat the cacop as a nop */ +- if (check_plv(ctx)) { +- return false; +- } +- return true; +-} +- +-static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) +-{ +- TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- +- if (!avail_LSPW(ctx)) { +- return true; +- } +- +- if (check_plv(ctx)) { +- return false; +- } +- gen_helper_ldpte(tcg_env, src1, tcg_constant_tl(a->imm), mem_idx); +- return true; +-} +- +-static bool trans_lddir(DisasContext *ctx, arg_lddir *a) +-{ +- TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx); +- TCGv src = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- +- if (!avail_LSPW(ctx)) { +- return true; +- } +- +- if (check_plv(ctx)) { +- return false; +- } +- gen_helper_lddir(dest, tcg_env, src, tcg_constant_tl(a->imm), mem_idx); +- return true; +-} +- +-static bool trans_ertn(DisasContext *ctx, arg_ertn *a) +-{ +- if (check_plv(ctx)) { +- return false; +- } +- gen_helper_ertn(tcg_env); +- ctx->base.is_jmp = DISAS_EXIT; +- return true; +-} +- +-static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) +-{ +- if (check_plv(ctx)) { +- return false; +- } +- generate_exception(ctx, EXCCODE_DBP); +- return true; +-} +- +-static bool trans_idle(DisasContext *ctx, arg_idle *a) +-{ +- if (check_plv(ctx)) { +- return false; +- } +- +- tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4); +- gen_helper_idle(tcg_env); +- ctx->base.is_jmp = DISAS_NORETURN; +- return true; +-} +-#endif +diff --git a/target/loongarch/insn_trans/trans_shift.c.inc b/target/loongarch/insn_trans/trans_shift.c.inc +deleted file mode 100644 +index 2f4bd6f..0000000 +--- a/target/loongarch/insn_trans/trans_shift.c.inc ++++ /dev/null +@@ -1,99 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-static void gen_sll_w(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- tcg_gen_andi_tl(t0, src2, 0x1f); +- tcg_gen_shl_tl(dest, src1, t0); +-} +- +-static void gen_srl_w(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- tcg_gen_andi_tl(t0, src2, 0x1f); +- tcg_gen_shr_tl(dest, src1, t0); +-} +- +-static void gen_sra_w(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- tcg_gen_andi_tl(t0, src2, 0x1f); +- tcg_gen_sar_tl(dest, src1, t0); +-} +- +-static void gen_sll_d(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- tcg_gen_andi_tl(t0, src2, 0x3f); +- tcg_gen_shl_tl(dest, src1, t0); +-} +- +-static void gen_srl_d(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- tcg_gen_andi_tl(t0, src2, 0x3f); +- tcg_gen_shr_tl(dest, src1, t0); +-} +- +-static void gen_sra_d(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- tcg_gen_andi_tl(t0, src2, 0x3f); +- tcg_gen_sar_tl(dest, src1, t0); +-} +- +-static void gen_rotr_w(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv_i32 t1 = tcg_temp_new_i32(); +- TCGv_i32 t2 = tcg_temp_new_i32(); +- TCGv t0 = tcg_temp_new(); +- +- tcg_gen_andi_tl(t0, src2, 0x1f); +- +- tcg_gen_trunc_tl_i32(t1, src1); +- tcg_gen_trunc_tl_i32(t2, t0); +- +- tcg_gen_rotr_i32(t1, t1, t2); +- tcg_gen_ext_i32_tl(dest, t1); +-} +- +-static void gen_rotr_d(TCGv dest, TCGv src1, TCGv src2) +-{ +- TCGv t0 = tcg_temp_new(); +- tcg_gen_andi_tl(t0, src2, 0x3f); +- tcg_gen_rotr_tl(dest, src1, t0); +-} +- +-static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) +-{ +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO); +- +- if (!avail_64(ctx)) { +- return false; +- } +- +- tcg_gen_sextract_tl(dest, src1, a->imm, 32 - a->imm); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; +-} +- +-TRANS(sll_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) +-TRANS(srl_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_srl_w) +-TRANS(sra_w, ALL, gen_rrr, EXT_SIGN, EXT_NONE, EXT_SIGN, gen_sra_w) +-TRANS(sll_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sll_d) +-TRANS(srl_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_srl_d) +-TRANS(sra_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sra_d) +-TRANS(rotr_w, 64, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_rotr_w) +-TRANS(rotr_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rotr_d) +-TRANS(slli_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) +-TRANS(slli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) +-TRANS(srli_w, ALL, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) +-TRANS(srli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) +-TRANS(srai_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) +-TRANS(rotri_w, 64, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) +-TRANS(rotri_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) +diff --git a/target/loongarch/insn_trans/trans_vec.c.inc b/target/loongarch/insn_trans/trans_vec.c.inc +deleted file mode 100644 +index 92b1d22..0000000 +--- a/target/loongarch/insn_trans/trans_vec.c.inc ++++ /dev/null +@@ -1,5511 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * LoongArch vector translate functions +- * Copyright (c) 2022-2023 Loongson Technology Corporation Limited +- */ +- +-static bool check_vec(DisasContext *ctx, uint32_t oprsz) +-{ +- if ((oprsz == 16) && ((ctx->base.tb->flags & HW_FLAGS_EUEN_SXE) == 0)) { +- generate_exception(ctx, EXCCODE_SXD); +- return false; +- } +- +- if ((oprsz == 32) && ((ctx->base.tb->flags & HW_FLAGS_EUEN_ASXE) == 0)) { +- generate_exception(ctx, EXCCODE_ASXD); +- return false; +- } +- +- return true; +-} +- +-static bool gen_vvvv_ptr_vl(DisasContext *ctx, arg_vvvv *a, uint32_t oprsz, +- gen_helper_gvec_4_ptr *fn) +-{ +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_gvec_4_ptr(vec_full_offset(a->vd), +- vec_full_offset(a->vj), +- vec_full_offset(a->vk), +- vec_full_offset(a->va), +- tcg_env, +- oprsz, ctx->vl / 8, 0, fn); +- return true; +-} +- +-static bool gen_vvvv_ptr(DisasContext *ctx, arg_vvvv *a, +- gen_helper_gvec_4_ptr *fn) +-{ +- return gen_vvvv_ptr_vl(ctx, a, 16, fn); +-} +- +-static bool gen_xxxx_ptr(DisasContext *ctx, arg_vvvv *a, +- gen_helper_gvec_4_ptr *fn) +-{ +- return gen_vvvv_ptr_vl(ctx, a, 32, fn); +-} +- +-static bool gen_vvvv_vl(DisasContext *ctx, arg_vvvv *a, uint32_t oprsz, +- gen_helper_gvec_4 *fn) +-{ +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_gvec_4_ool(vec_full_offset(a->vd), +- vec_full_offset(a->vj), +- vec_full_offset(a->vk), +- vec_full_offset(a->va), +- oprsz, ctx->vl / 8, 0, fn); +- return true; +-} +- +-static bool gen_vvvv(DisasContext *ctx, arg_vvvv *a, +- gen_helper_gvec_4 *fn) +-{ +- return gen_vvvv_vl(ctx, a, 16, fn); +-} +- +-static bool gen_xxxx(DisasContext *ctx, arg_vvvv *a, +- gen_helper_gvec_4 *fn) +-{ +- return gen_vvvv_vl(ctx, a, 32, fn); +-} +- +-static bool gen_vvv_ptr_vl(DisasContext *ctx, arg_vvv *a, uint32_t oprsz, +- gen_helper_gvec_3_ptr *fn) +-{ +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- tcg_gen_gvec_3_ptr(vec_full_offset(a->vd), +- vec_full_offset(a->vj), +- vec_full_offset(a->vk), +- tcg_env, +- oprsz, ctx->vl / 8, 0, fn); +- return true; +-} +- +-static bool gen_vvv_ptr(DisasContext *ctx, arg_vvv *a, +- gen_helper_gvec_3_ptr *fn) +-{ +- return gen_vvv_ptr_vl(ctx, a, 16, fn); +-} +- +-static bool gen_xxx_ptr(DisasContext *ctx, arg_vvv *a, +- gen_helper_gvec_3_ptr *fn) +-{ +- return gen_vvv_ptr_vl(ctx, a, 32, fn); +-} +- +-static bool gen_vvv_vl(DisasContext *ctx, arg_vvv *a, uint32_t oprsz, +- gen_helper_gvec_3 *fn) +-{ +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_gvec_3_ool(vec_full_offset(a->vd), +- vec_full_offset(a->vj), +- vec_full_offset(a->vk), +- oprsz, ctx->vl / 8, 0, fn); +- return true; +-} +- +-static bool gen_vvv(DisasContext *ctx, arg_vvv *a, gen_helper_gvec_3 *fn) +-{ +- return gen_vvv_vl(ctx, a, 16, fn); +-} +- +-static bool gen_xxx(DisasContext *ctx, arg_vvv *a, gen_helper_gvec_3 *fn) +-{ +- return gen_vvv_vl(ctx, a, 32, fn); +-} +- +-static bool gen_vv_ptr_vl(DisasContext *ctx, arg_vv *a, uint32_t oprsz, +- gen_helper_gvec_2_ptr *fn) +-{ +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_gvec_2_ptr(vec_full_offset(a->vd), +- vec_full_offset(a->vj), +- tcg_env, +- oprsz, ctx->vl / 8, 0, fn); +- return true; +-} +- +-static bool gen_vv_ptr(DisasContext *ctx, arg_vv *a, +- gen_helper_gvec_2_ptr *fn) +-{ +- return gen_vv_ptr_vl(ctx, a, 16, fn); +-} +- +-static bool gen_xx_ptr(DisasContext *ctx, arg_vv *a, +- gen_helper_gvec_2_ptr *fn) +-{ +- return gen_vv_ptr_vl(ctx, a, 32, fn); +-} +- +-static bool gen_vv_vl(DisasContext *ctx, arg_vv *a, uint32_t oprsz, +- gen_helper_gvec_2 *fn) +-{ +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_gvec_2_ool(vec_full_offset(a->vd), +- vec_full_offset(a->vj), +- oprsz, ctx->vl / 8, 0, fn); +- return true; +-} +- +-static bool gen_vv(DisasContext *ctx, arg_vv *a, gen_helper_gvec_2 *fn) +-{ +- return gen_vv_vl(ctx, a, 16, fn); +-} +- +-static bool gen_xx(DisasContext *ctx, arg_vv *a, gen_helper_gvec_2 *fn) +-{ +- return gen_vv_vl(ctx, a, 32, fn); +-} +- +-static bool gen_vv_i_vl(DisasContext *ctx, arg_vv_i *a, uint32_t oprsz, +- gen_helper_gvec_2i *fn) +-{ +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_gvec_2i_ool(vec_full_offset(a->vd), +- vec_full_offset(a->vj), +- tcg_constant_i64(a->imm), +- oprsz, ctx->vl / 8, 0, fn); +- return true; +-} +- +-static bool gen_vv_i(DisasContext *ctx, arg_vv_i *a, gen_helper_gvec_2i *fn) +-{ +- return gen_vv_i_vl(ctx, a, 16, fn); +-} +- +-static bool gen_xx_i(DisasContext *ctx, arg_vv_i *a, gen_helper_gvec_2i *fn) +-{ +- return gen_vv_i_vl(ctx, a, 32, fn); +-} +- +-static bool gen_cv_vl(DisasContext *ctx, arg_cv *a, uint32_t sz, +- void (*func)(TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32)) +-{ +- if (!check_vec(ctx, sz)) { +- return true; +- } +- +- TCGv_i32 vj = tcg_constant_i32(a->vj); +- TCGv_i32 cd = tcg_constant_i32(a->cd); +- TCGv_i32 oprsz = tcg_constant_i32(sz); +- +- func(tcg_env, oprsz, cd, vj); +- return true; +-} +- +-static bool gen_cv(DisasContext *ctx, arg_cv *a, +- void (*func)(TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32)) +-{ +- return gen_cv_vl(ctx, a, 16, func); +-} +- +-static bool gen_cx(DisasContext *ctx, arg_cv *a, +- void (*func)(TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32)) +-{ +- return gen_cv_vl(ctx, a, 32, func); +-} +- +-static bool gvec_vvv_vl(DisasContext *ctx, arg_vvv *a, +- uint32_t oprsz, MemOp mop, +- void (*func)(unsigned, uint32_t, uint32_t, +- uint32_t, uint32_t, uint32_t)) +-{ +- uint32_t vd_ofs = vec_full_offset(a->vd); +- uint32_t vj_ofs = vec_full_offset(a->vj); +- uint32_t vk_ofs = vec_full_offset(a->vk); +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- func(mop, vd_ofs, vj_ofs, vk_ofs, oprsz, ctx->vl / 8); +- return true; +-} +- +-static bool gvec_vvv(DisasContext *ctx, arg_vvv *a, MemOp mop, +- void (*func)(unsigned, uint32_t, uint32_t, +- uint32_t, uint32_t, uint32_t)) +-{ +- return gvec_vvv_vl(ctx, a, 16, mop, func); +-} +- +-static bool gvec_xxx(DisasContext *ctx, arg_vvv *a, MemOp mop, +- void (*func)(unsigned, uint32_t, uint32_t, +- uint32_t, uint32_t, uint32_t)) +-{ +- return gvec_vvv_vl(ctx, a, 32, mop, func); +-} +- +-static bool gvec_vv_vl(DisasContext *ctx, arg_vv *a, +- uint32_t oprsz, MemOp mop, +- void (*func)(unsigned, uint32_t, uint32_t, +- uint32_t, uint32_t)) +-{ +- uint32_t vd_ofs = vec_full_offset(a->vd); +- uint32_t vj_ofs = vec_full_offset(a->vj); +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- func(mop, vd_ofs, vj_ofs, oprsz, ctx->vl / 8); +- return true; +-} +- +- +-static bool gvec_vv(DisasContext *ctx, arg_vv *a, MemOp mop, +- void (*func)(unsigned, uint32_t, uint32_t, +- uint32_t, uint32_t)) +-{ +- return gvec_vv_vl(ctx, a, 16, mop, func); +-} +- +-static bool gvec_xx(DisasContext *ctx, arg_vv *a, MemOp mop, +- void (*func)(unsigned, uint32_t, uint32_t, +- uint32_t, uint32_t)) +-{ +- return gvec_vv_vl(ctx, a, 32, mop, func); +-} +- +-static bool gvec_vv_i_vl(DisasContext *ctx, arg_vv_i *a, +- uint32_t oprsz, MemOp mop, +- void (*func)(unsigned, uint32_t, uint32_t, +- int64_t, uint32_t, uint32_t)) +-{ +- uint32_t vd_ofs = vec_full_offset(a->vd); +- uint32_t vj_ofs = vec_full_offset(a->vj); +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- func(mop, vd_ofs, vj_ofs, a->imm, oprsz, ctx->vl / 8); +- return true; +-} +- +-static bool gvec_vv_i(DisasContext *ctx, arg_vv_i *a, MemOp mop, +- void (*func)(unsigned, uint32_t, uint32_t, +- int64_t, uint32_t, uint32_t)) +-{ +- return gvec_vv_i_vl(ctx, a, 16, mop, func); +-} +- +-static bool gvec_xx_i(DisasContext *ctx, arg_vv_i *a, MemOp mop, +- void (*func)(unsigned, uint32_t, uint32_t, +- int64_t, uint32_t, uint32_t)) +-{ +- return gvec_vv_i_vl(ctx,a, 32, mop, func); +-} +- +-static bool gvec_subi_vl(DisasContext *ctx, arg_vv_i *a, +- uint32_t oprsz, MemOp mop) +-{ +- uint32_t vd_ofs = vec_full_offset(a->vd); +- uint32_t vj_ofs = vec_full_offset(a->vj); +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_gvec_addi(mop, vd_ofs, vj_ofs, -a->imm, oprsz, ctx->vl / 8); +- return true; +-} +- +-static bool gvec_subi(DisasContext *ctx, arg_vv_i *a, MemOp mop) +-{ +- return gvec_subi_vl(ctx, a, 16, mop); +-} +- +-static bool gvec_xsubi(DisasContext *ctx, arg_vv_i *a, MemOp mop) +-{ +- return gvec_subi_vl(ctx, a, 32, mop); +-} +- +-TRANS(vadd_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_add) +-TRANS(vadd_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_add) +-TRANS(vadd_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_add) +-TRANS(vadd_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_add) +-TRANS(xvadd_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_add) +-TRANS(xvadd_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_add) +-TRANS(xvadd_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_add) +-TRANS(xvadd_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_add) +- +-static bool gen_vaddsub_q_vl(DisasContext *ctx, arg_vvv *a, uint32_t oprsz, +- void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, +- TCGv_i64, TCGv_i64, TCGv_i64)) +-{ +- int i; +- TCGv_i64 rh, rl, ah, al, bh, bl; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- rh = tcg_temp_new_i64(); +- rl = tcg_temp_new_i64(); +- ah = tcg_temp_new_i64(); +- al = tcg_temp_new_i64(); +- bh = tcg_temp_new_i64(); +- bl = tcg_temp_new_i64(); +- +- for (i = 0; i < oprsz / 16; i++) { +- get_vreg64(ah, a->vj, 1 + i * 2); +- get_vreg64(al, a->vj, i * 2); +- get_vreg64(bh, a->vk, 1 + i * 2); +- get_vreg64(bl, a->vk, i * 2); +- +- func(rl, rh, al, ah, bl, bh); +- +- set_vreg64(rh, a->vd, 1 + i * 2); +- set_vreg64(rl, a->vd, i * 2); +- } +- return true; +-} +- +-static bool gen_vaddsub_q(DisasContext *ctx, arg_vvv *a, +- void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, +- TCGv_i64, TCGv_i64, TCGv_i64)) +-{ +- return gen_vaddsub_q_vl(ctx, a, 16, func); +-} +- +-static bool gen_xvaddsub_q(DisasContext *ctx, arg_vvv *a, +- void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, +- TCGv_i64, TCGv_i64, TCGv_i64)) +-{ +- return gen_vaddsub_q_vl(ctx, a, 32, func); +-} +- +-TRANS(vsub_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_sub) +-TRANS(vsub_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_sub) +-TRANS(vsub_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_sub) +-TRANS(vsub_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_sub) +-TRANS(xvsub_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_sub) +-TRANS(xvsub_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_sub) +-TRANS(xvsub_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_sub) +-TRANS(xvsub_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_sub) +- +-TRANS(vadd_q, LSX, gen_vaddsub_q, tcg_gen_add2_i64) +-TRANS(vsub_q, LSX, gen_vaddsub_q, tcg_gen_sub2_i64) +-TRANS(xvadd_q, LASX, gen_xvaddsub_q, tcg_gen_add2_i64) +-TRANS(xvsub_q, LASX, gen_xvaddsub_q, tcg_gen_sub2_i64) +- +-TRANS(vaddi_bu, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_addi) +-TRANS(vaddi_hu, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_addi) +-TRANS(vaddi_wu, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_addi) +-TRANS(vaddi_du, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_addi) +-TRANS(vsubi_bu, LSX, gvec_subi, MO_8) +-TRANS(vsubi_hu, LSX, gvec_subi, MO_16) +-TRANS(vsubi_wu, LSX, gvec_subi, MO_32) +-TRANS(vsubi_du, LSX, gvec_subi, MO_64) +-TRANS(xvaddi_bu, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_addi) +-TRANS(xvaddi_hu, LASX, gvec_xx_i, MO_16, tcg_gen_gvec_addi) +-TRANS(xvaddi_wu, LASX, gvec_xx_i, MO_32, tcg_gen_gvec_addi) +-TRANS(xvaddi_du, LASX, gvec_xx_i, MO_64, tcg_gen_gvec_addi) +-TRANS(xvsubi_bu, LASX, gvec_xsubi, MO_8) +-TRANS(xvsubi_hu, LASX, gvec_xsubi, MO_16) +-TRANS(xvsubi_wu, LASX, gvec_xsubi, MO_32) +-TRANS(xvsubi_du, LASX, gvec_xsubi, MO_64) +- +-TRANS(vneg_b, LSX, gvec_vv, MO_8, tcg_gen_gvec_neg) +-TRANS(vneg_h, LSX, gvec_vv, MO_16, tcg_gen_gvec_neg) +-TRANS(vneg_w, LSX, gvec_vv, MO_32, tcg_gen_gvec_neg) +-TRANS(vneg_d, LSX, gvec_vv, MO_64, tcg_gen_gvec_neg) +-TRANS(xvneg_b, LASX, gvec_xx, MO_8, tcg_gen_gvec_neg) +-TRANS(xvneg_h, LASX, gvec_xx, MO_16, tcg_gen_gvec_neg) +-TRANS(xvneg_w, LASX, gvec_xx, MO_32, tcg_gen_gvec_neg) +-TRANS(xvneg_d, LASX, gvec_xx, MO_64, tcg_gen_gvec_neg) +- +-TRANS(vsadd_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_ssadd) +-TRANS(vsadd_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_ssadd) +-TRANS(vsadd_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_ssadd) +-TRANS(vsadd_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_ssadd) +-TRANS(vsadd_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_usadd) +-TRANS(vsadd_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_usadd) +-TRANS(vsadd_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_usadd) +-TRANS(vsadd_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_usadd) +-TRANS(vssub_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_sssub) +-TRANS(vssub_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_sssub) +-TRANS(vssub_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_sssub) +-TRANS(vssub_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_sssub) +-TRANS(vssub_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_ussub) +-TRANS(vssub_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_ussub) +-TRANS(vssub_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_ussub) +-TRANS(vssub_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_ussub) +- +-TRANS(xvsadd_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_ssadd) +-TRANS(xvsadd_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_ssadd) +-TRANS(xvsadd_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_ssadd) +-TRANS(xvsadd_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_ssadd) +-TRANS(xvsadd_bu, LASX, gvec_xxx, MO_8, tcg_gen_gvec_usadd) +-TRANS(xvsadd_hu, LASX, gvec_xxx, MO_16, tcg_gen_gvec_usadd) +-TRANS(xvsadd_wu, LASX, gvec_xxx, MO_32, tcg_gen_gvec_usadd) +-TRANS(xvsadd_du, LASX, gvec_xxx, MO_64, tcg_gen_gvec_usadd) +-TRANS(xvssub_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_sssub) +-TRANS(xvssub_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_sssub) +-TRANS(xvssub_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_sssub) +-TRANS(xvssub_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_sssub) +-TRANS(xvssub_bu, LASX, gvec_xxx, MO_8, tcg_gen_gvec_ussub) +-TRANS(xvssub_hu, LASX, gvec_xxx, MO_16, tcg_gen_gvec_ussub) +-TRANS(xvssub_wu, LASX, gvec_xxx, MO_32, tcg_gen_gvec_ussub) +-TRANS(xvssub_du, LASX, gvec_xxx, MO_64, tcg_gen_gvec_ussub) +- +-TRANS(vhaddw_h_b, LSX, gen_vvv, gen_helper_vhaddw_h_b) +-TRANS(vhaddw_w_h, LSX, gen_vvv, gen_helper_vhaddw_w_h) +-TRANS(vhaddw_d_w, LSX, gen_vvv, gen_helper_vhaddw_d_w) +-TRANS(vhaddw_q_d, LSX, gen_vvv, gen_helper_vhaddw_q_d) +-TRANS(vhaddw_hu_bu, LSX, gen_vvv, gen_helper_vhaddw_hu_bu) +-TRANS(vhaddw_wu_hu, LSX, gen_vvv, gen_helper_vhaddw_wu_hu) +-TRANS(vhaddw_du_wu, LSX, gen_vvv, gen_helper_vhaddw_du_wu) +-TRANS(vhaddw_qu_du, LSX, gen_vvv, gen_helper_vhaddw_qu_du) +-TRANS(vhsubw_h_b, LSX, gen_vvv, gen_helper_vhsubw_h_b) +-TRANS(vhsubw_w_h, LSX, gen_vvv, gen_helper_vhsubw_w_h) +-TRANS(vhsubw_d_w, LSX, gen_vvv, gen_helper_vhsubw_d_w) +-TRANS(vhsubw_q_d, LSX, gen_vvv, gen_helper_vhsubw_q_d) +-TRANS(vhsubw_hu_bu, LSX, gen_vvv, gen_helper_vhsubw_hu_bu) +-TRANS(vhsubw_wu_hu, LSX, gen_vvv, gen_helper_vhsubw_wu_hu) +-TRANS(vhsubw_du_wu, LSX, gen_vvv, gen_helper_vhsubw_du_wu) +-TRANS(vhsubw_qu_du, LSX, gen_vvv, gen_helper_vhsubw_qu_du) +- +-TRANS(xvhaddw_h_b, LASX, gen_xxx, gen_helper_vhaddw_h_b) +-TRANS(xvhaddw_w_h, LASX, gen_xxx, gen_helper_vhaddw_w_h) +-TRANS(xvhaddw_d_w, LASX, gen_xxx, gen_helper_vhaddw_d_w) +-TRANS(xvhaddw_q_d, LASX, gen_xxx, gen_helper_vhaddw_q_d) +-TRANS(xvhaddw_hu_bu, LASX, gen_xxx, gen_helper_vhaddw_hu_bu) +-TRANS(xvhaddw_wu_hu, LASX, gen_xxx, gen_helper_vhaddw_wu_hu) +-TRANS(xvhaddw_du_wu, LASX, gen_xxx, gen_helper_vhaddw_du_wu) +-TRANS(xvhaddw_qu_du, LASX, gen_xxx, gen_helper_vhaddw_qu_du) +-TRANS(xvhsubw_h_b, LASX, gen_xxx, gen_helper_vhsubw_h_b) +-TRANS(xvhsubw_w_h, LASX, gen_xxx, gen_helper_vhsubw_w_h) +-TRANS(xvhsubw_d_w, LASX, gen_xxx, gen_helper_vhsubw_d_w) +-TRANS(xvhsubw_q_d, LASX, gen_xxx, gen_helper_vhsubw_q_d) +-TRANS(xvhsubw_hu_bu, LASX, gen_xxx, gen_helper_vhsubw_hu_bu) +-TRANS(xvhsubw_wu_hu, LASX, gen_xxx, gen_helper_vhsubw_wu_hu) +-TRANS(xvhsubw_du_wu, LASX, gen_xxx, gen_helper_vhsubw_du_wu) +-TRANS(xvhsubw_qu_du, LASX, gen_xxx, gen_helper_vhsubw_qu_du) +- +-static void gen_vaddwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- +- /* Sign-extend the even elements from a */ +- tcg_gen_shli_vec(vece, t1, a, halfbits); +- tcg_gen_sari_vec(vece, t1, t1, halfbits); +- +- /* Sign-extend the even elements from b */ +- tcg_gen_shli_vec(vece, t2, b, halfbits); +- tcg_gen_sari_vec(vece, t2, t2, halfbits); +- +- tcg_gen_add_vec(vece, t, t1, t2); +-} +- +-static void gen_vaddwev_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_ext16s_i32(t1, a); +- tcg_gen_ext16s_i32(t2, b); +- tcg_gen_add_i32(t, t1, t2); +-} +- +-static void gen_vaddwev_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_ext32s_i64(t1, a); +- tcg_gen_ext32s_i64(t2, b); +- tcg_gen_add_i64(t, t1, t2); +-} +- +-static void do_vaddwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shli_vec, INDEX_op_sari_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vaddwev_s, +- .fno = gen_helper_vaddwev_h_b, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vaddwev_w_h, +- .fniv = gen_vaddwev_s, +- .fno = gen_helper_vaddwev_w_h, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vaddwev_d_w, +- .fniv = gen_vaddwev_s, +- .fno = gen_helper_vaddwev_d_w, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- { +- .fno = gen_helper_vaddwev_q_d, +- .vece = MO_128 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vaddwev_h_b, LSX, gvec_vvv, MO_8, do_vaddwev_s) +-TRANS(vaddwev_w_h, LSX, gvec_vvv, MO_16, do_vaddwev_s) +-TRANS(vaddwev_d_w, LSX, gvec_vvv, MO_32, do_vaddwev_s) +-TRANS(vaddwev_q_d, LSX, gvec_vvv, MO_64, do_vaddwev_s) +-TRANS(xvaddwev_h_b, LASX, gvec_xxx, MO_8, do_vaddwev_s) +-TRANS(xvaddwev_w_h, LASX, gvec_xxx, MO_16, do_vaddwev_s) +-TRANS(xvaddwev_d_w, LASX, gvec_xxx, MO_32, do_vaddwev_s) +-TRANS(xvaddwev_q_d, LASX, gvec_xxx, MO_64, do_vaddwev_s) +- +-static void gen_vaddwod_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_sari_i32(t1, a, 16); +- tcg_gen_sari_i32(t2, b, 16); +- tcg_gen_add_i32(t, t1, t2); +-} +- +-static void gen_vaddwod_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_sari_i64(t1, a, 32); +- tcg_gen_sari_i64(t2, b, 32); +- tcg_gen_add_i64(t, t1, t2); +-} +- +-static void gen_vaddwod_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- +- /* Sign-extend the odd elements for vector */ +- tcg_gen_sari_vec(vece, t1, a, halfbits); +- tcg_gen_sari_vec(vece, t2, b, halfbits); +- +- tcg_gen_add_vec(vece, t, t1, t2); +-} +- +-static void do_vaddwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_sari_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vaddwod_s, +- .fno = gen_helper_vaddwod_h_b, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vaddwod_w_h, +- .fniv = gen_vaddwod_s, +- .fno = gen_helper_vaddwod_w_h, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vaddwod_d_w, +- .fniv = gen_vaddwod_s, +- .fno = gen_helper_vaddwod_d_w, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- { +- .fno = gen_helper_vaddwod_q_d, +- .vece = MO_128 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vaddwod_h_b, LSX, gvec_vvv, MO_8, do_vaddwod_s) +-TRANS(vaddwod_w_h, LSX, gvec_vvv, MO_16, do_vaddwod_s) +-TRANS(vaddwod_d_w, LSX, gvec_vvv, MO_32, do_vaddwod_s) +-TRANS(vaddwod_q_d, LSX, gvec_vvv, MO_64, do_vaddwod_s) +-TRANS(xvaddwod_h_b, LASX, gvec_xxx, MO_8, do_vaddwod_s) +-TRANS(xvaddwod_w_h, LASX, gvec_xxx, MO_16, do_vaddwod_s) +-TRANS(xvaddwod_d_w, LASX, gvec_xxx, MO_32, do_vaddwod_s) +-TRANS(xvaddwod_q_d, LASX, gvec_xxx, MO_64, do_vaddwod_s) +- +- +-static void gen_vsubwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- +- /* Sign-extend the even elements from a */ +- tcg_gen_shli_vec(vece, t1, a, halfbits); +- tcg_gen_sari_vec(vece, t1, t1, halfbits); +- +- /* Sign-extend the even elements from b */ +- tcg_gen_shli_vec(vece, t2, b, halfbits); +- tcg_gen_sari_vec(vece, t2, t2, halfbits); +- +- tcg_gen_sub_vec(vece, t, t1, t2); +-} +- +-static void gen_vsubwev_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_ext16s_i32(t1, a); +- tcg_gen_ext16s_i32(t2, b); +- tcg_gen_sub_i32(t, t1, t2); +-} +- +-static void gen_vsubwev_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_ext32s_i64(t1, a); +- tcg_gen_ext32s_i64(t2, b); +- tcg_gen_sub_i64(t, t1, t2); +-} +- +-static void do_vsubwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shli_vec, INDEX_op_sari_vec, INDEX_op_sub_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vsubwev_s, +- .fno = gen_helper_vsubwev_h_b, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vsubwev_w_h, +- .fniv = gen_vsubwev_s, +- .fno = gen_helper_vsubwev_w_h, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vsubwev_d_w, +- .fniv = gen_vsubwev_s, +- .fno = gen_helper_vsubwev_d_w, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- { +- .fno = gen_helper_vsubwev_q_d, +- .vece = MO_128 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vsubwev_h_b, LSX, gvec_vvv, MO_8, do_vsubwev_s) +-TRANS(vsubwev_w_h, LSX, gvec_vvv, MO_16, do_vsubwev_s) +-TRANS(vsubwev_d_w, LSX, gvec_vvv, MO_32, do_vsubwev_s) +-TRANS(vsubwev_q_d, LSX, gvec_vvv, MO_64, do_vsubwev_s) +-TRANS(xvsubwev_h_b, LASX, gvec_xxx, MO_8, do_vsubwev_s) +-TRANS(xvsubwev_w_h, LASX, gvec_xxx, MO_16, do_vsubwev_s) +-TRANS(xvsubwev_d_w, LASX, gvec_xxx, MO_32, do_vsubwev_s) +-TRANS(xvsubwev_q_d, LASX, gvec_xxx, MO_64, do_vsubwev_s) +- +-static void gen_vsubwod_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- +- /* Sign-extend the odd elements for vector */ +- tcg_gen_sari_vec(vece, t1, a, halfbits); +- tcg_gen_sari_vec(vece, t2, b, halfbits); +- +- tcg_gen_sub_vec(vece, t, t1, t2); +-} +- +-static void gen_vsubwod_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_sari_i32(t1, a, 16); +- tcg_gen_sari_i32(t2, b, 16); +- tcg_gen_sub_i32(t, t1, t2); +-} +- +-static void gen_vsubwod_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_sari_i64(t1, a, 32); +- tcg_gen_sari_i64(t2, b, 32); +- tcg_gen_sub_i64(t, t1, t2); +-} +- +-static void do_vsubwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_sari_vec, INDEX_op_sub_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vsubwod_s, +- .fno = gen_helper_vsubwod_h_b, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vsubwod_w_h, +- .fniv = gen_vsubwod_s, +- .fno = gen_helper_vsubwod_w_h, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vsubwod_d_w, +- .fniv = gen_vsubwod_s, +- .fno = gen_helper_vsubwod_d_w, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- { +- .fno = gen_helper_vsubwod_q_d, +- .vece = MO_128 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vsubwod_h_b, LSX, gvec_vvv, MO_8, do_vsubwod_s) +-TRANS(vsubwod_w_h, LSX, gvec_vvv, MO_16, do_vsubwod_s) +-TRANS(vsubwod_d_w, LSX, gvec_vvv, MO_32, do_vsubwod_s) +-TRANS(vsubwod_q_d, LSX, gvec_vvv, MO_64, do_vsubwod_s) +-TRANS(xvsubwod_h_b, LASX, gvec_xxx, MO_8, do_vsubwod_s) +-TRANS(xvsubwod_w_h, LASX, gvec_xxx, MO_16, do_vsubwod_s) +-TRANS(xvsubwod_d_w, LASX, gvec_xxx, MO_32, do_vsubwod_s) +-TRANS(xvsubwod_q_d, LASX, gvec_xxx, MO_64, do_vsubwod_s) +- +-static void gen_vaddwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, t3; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- t3 = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); +- tcg_gen_and_vec(vece, t1, a, t3); +- tcg_gen_and_vec(vece, t2, b, t3); +- tcg_gen_add_vec(vece, t, t1, t2); +-} +- +-static void gen_vaddwev_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_ext16u_i32(t1, a); +- tcg_gen_ext16u_i32(t2, b); +- tcg_gen_add_i32(t, t1, t2); +-} +- +-static void gen_vaddwev_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_ext32u_i64(t1, a); +- tcg_gen_ext32u_i64(t2, b); +- tcg_gen_add_i64(t, t1, t2); +-} +- +-static void do_vaddwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vaddwev_u, +- .fno = gen_helper_vaddwev_h_bu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vaddwev_w_hu, +- .fniv = gen_vaddwev_u, +- .fno = gen_helper_vaddwev_w_hu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vaddwev_d_wu, +- .fniv = gen_vaddwev_u, +- .fno = gen_helper_vaddwev_d_wu, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- { +- .fno = gen_helper_vaddwev_q_du, +- .vece = MO_128 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vaddwev_h_bu, LSX, gvec_vvv, MO_8, do_vaddwev_u) +-TRANS(vaddwev_w_hu, LSX, gvec_vvv, MO_16, do_vaddwev_u) +-TRANS(vaddwev_d_wu, LSX, gvec_vvv, MO_32, do_vaddwev_u) +-TRANS(vaddwev_q_du, LSX, gvec_vvv, MO_64, do_vaddwev_u) +-TRANS(xvaddwev_h_bu, LASX, gvec_xxx, MO_8, do_vaddwev_u) +-TRANS(xvaddwev_w_hu, LASX, gvec_xxx, MO_16, do_vaddwev_u) +-TRANS(xvaddwev_d_wu, LASX, gvec_xxx, MO_32, do_vaddwev_u) +-TRANS(xvaddwev_q_du, LASX, gvec_xxx, MO_64, do_vaddwev_u) +- +-static void gen_vaddwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- +- /* Zero-extend the odd elements for vector */ +- tcg_gen_shri_vec(vece, t1, a, halfbits); +- tcg_gen_shri_vec(vece, t2, b, halfbits); +- +- tcg_gen_add_vec(vece, t, t1, t2); +-} +- +-static void gen_vaddwod_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_shri_i32(t1, a, 16); +- tcg_gen_shri_i32(t2, b, 16); +- tcg_gen_add_i32(t, t1, t2); +-} +- +-static void gen_vaddwod_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_shri_i64(t1, a, 32); +- tcg_gen_shri_i64(t2, b, 32); +- tcg_gen_add_i64(t, t1, t2); +-} +- +-static void do_vaddwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shri_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vaddwod_u, +- .fno = gen_helper_vaddwod_h_bu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vaddwod_w_hu, +- .fniv = gen_vaddwod_u, +- .fno = gen_helper_vaddwod_w_hu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vaddwod_d_wu, +- .fniv = gen_vaddwod_u, +- .fno = gen_helper_vaddwod_d_wu, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- { +- .fno = gen_helper_vaddwod_q_du, +- .vece = MO_128 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vaddwod_h_bu, LSX, gvec_vvv, MO_8, do_vaddwod_u) +-TRANS(vaddwod_w_hu, LSX, gvec_vvv, MO_16, do_vaddwod_u) +-TRANS(vaddwod_d_wu, LSX, gvec_vvv, MO_32, do_vaddwod_u) +-TRANS(vaddwod_q_du, LSX, gvec_vvv, MO_64, do_vaddwod_u) +-TRANS(xvaddwod_h_bu, LASX, gvec_xxx, MO_8, do_vaddwod_u) +-TRANS(xvaddwod_w_hu, LASX, gvec_xxx, MO_16, do_vaddwod_u) +-TRANS(xvaddwod_d_wu, LASX, gvec_xxx, MO_32, do_vaddwod_u) +-TRANS(xvaddwod_q_du, LASX, gvec_xxx, MO_64, do_vaddwod_u) +- +-static void gen_vsubwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, t3; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- t3 = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); +- tcg_gen_and_vec(vece, t1, a, t3); +- tcg_gen_and_vec(vece, t2, b, t3); +- tcg_gen_sub_vec(vece, t, t1, t2); +-} +- +-static void gen_vsubwev_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_ext16u_i32(t1, a); +- tcg_gen_ext16u_i32(t2, b); +- tcg_gen_sub_i32(t, t1, t2); +-} +- +-static void gen_vsubwev_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_ext32u_i64(t1, a); +- tcg_gen_ext32u_i64(t2, b); +- tcg_gen_sub_i64(t, t1, t2); +-} +- +-static void do_vsubwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_sub_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vsubwev_u, +- .fno = gen_helper_vsubwev_h_bu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vsubwev_w_hu, +- .fniv = gen_vsubwev_u, +- .fno = gen_helper_vsubwev_w_hu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vsubwev_d_wu, +- .fniv = gen_vsubwev_u, +- .fno = gen_helper_vsubwev_d_wu, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- { +- .fno = gen_helper_vsubwev_q_du, +- .vece = MO_128 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vsubwev_h_bu, LSX, gvec_vvv, MO_8, do_vsubwev_u) +-TRANS(vsubwev_w_hu, LSX, gvec_vvv, MO_16, do_vsubwev_u) +-TRANS(vsubwev_d_wu, LSX, gvec_vvv, MO_32, do_vsubwev_u) +-TRANS(vsubwev_q_du, LSX, gvec_vvv, MO_64, do_vsubwev_u) +-TRANS(xvsubwev_h_bu, LASX, gvec_xxx, MO_8, do_vsubwev_u) +-TRANS(xvsubwev_w_hu, LASX, gvec_xxx, MO_16, do_vsubwev_u) +-TRANS(xvsubwev_d_wu, LASX, gvec_xxx, MO_32, do_vsubwev_u) +-TRANS(xvsubwev_q_du, LASX, gvec_xxx, MO_64, do_vsubwev_u) +- +-static void gen_vsubwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- +- /* Zero-extend the odd elements for vector */ +- tcg_gen_shri_vec(vece, t1, a, halfbits); +- tcg_gen_shri_vec(vece, t2, b, halfbits); +- +- tcg_gen_sub_vec(vece, t, t1, t2); +-} +- +-static void gen_vsubwod_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_shri_i32(t1, a, 16); +- tcg_gen_shri_i32(t2, b, 16); +- tcg_gen_sub_i32(t, t1, t2); +-} +- +-static void gen_vsubwod_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_shri_i64(t1, a, 32); +- tcg_gen_shri_i64(t2, b, 32); +- tcg_gen_sub_i64(t, t1, t2); +-} +- +-static void do_vsubwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shri_vec, INDEX_op_sub_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vsubwod_u, +- .fno = gen_helper_vsubwod_h_bu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vsubwod_w_hu, +- .fniv = gen_vsubwod_u, +- .fno = gen_helper_vsubwod_w_hu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vsubwod_d_wu, +- .fniv = gen_vsubwod_u, +- .fno = gen_helper_vsubwod_d_wu, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- { +- .fno = gen_helper_vsubwod_q_du, +- .vece = MO_128 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vsubwod_h_bu, LSX, gvec_vvv, MO_8, do_vsubwod_u) +-TRANS(vsubwod_w_hu, LSX, gvec_vvv, MO_16, do_vsubwod_u) +-TRANS(vsubwod_d_wu, LSX, gvec_vvv, MO_32, do_vsubwod_u) +-TRANS(vsubwod_q_du, LSX, gvec_vvv, MO_64, do_vsubwod_u) +-TRANS(xvsubwod_h_bu, LASX, gvec_xxx, MO_8, do_vsubwod_u) +-TRANS(xvsubwod_w_hu, LASX, gvec_xxx, MO_16, do_vsubwod_u) +-TRANS(xvsubwod_d_wu, LASX, gvec_xxx, MO_32, do_vsubwod_u) +-TRANS(xvsubwod_q_du, LASX, gvec_xxx, MO_64, do_vsubwod_u) +- +-static void gen_vaddwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, t3; +- +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- t3 = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, halfbits)); +- +- /* Zero-extend the even elements from a */ +- tcg_gen_and_vec(vece, t1, a, t3); +- +- /* Sign-extend the even elements from b */ +- tcg_gen_shli_vec(vece, t2, b, halfbits); +- tcg_gen_sari_vec(vece, t2, t2, halfbits); +- +- tcg_gen_add_vec(vece, t, t1, t2); +-} +- +-static void gen_vaddwev_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_ext16u_i32(t1, a); +- tcg_gen_ext16s_i32(t2, b); +- tcg_gen_add_i32(t, t1, t2); +-} +- +-static void gen_vaddwev_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_ext32u_i64(t1, a); +- tcg_gen_ext32s_i64(t2, b); +- tcg_gen_add_i64(t, t1, t2); +-} +- +-static void do_vaddwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shli_vec, INDEX_op_sari_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vaddwev_u_s, +- .fno = gen_helper_vaddwev_h_bu_b, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vaddwev_w_hu_h, +- .fniv = gen_vaddwev_u_s, +- .fno = gen_helper_vaddwev_w_hu_h, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vaddwev_d_wu_w, +- .fniv = gen_vaddwev_u_s, +- .fno = gen_helper_vaddwev_d_wu_w, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- { +- .fno = gen_helper_vaddwev_q_du_d, +- .vece = MO_128 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vaddwev_h_bu_b, LSX, gvec_vvv, MO_8, do_vaddwev_u_s) +-TRANS(vaddwev_w_hu_h, LSX, gvec_vvv, MO_16, do_vaddwev_u_s) +-TRANS(vaddwev_d_wu_w, LSX, gvec_vvv, MO_32, do_vaddwev_u_s) +-TRANS(vaddwev_q_du_d, LSX, gvec_vvv, MO_64, do_vaddwev_u_s) +-TRANS(xvaddwev_h_bu_b, LASX, gvec_xxx, MO_8, do_vaddwev_u_s) +-TRANS(xvaddwev_w_hu_h, LASX, gvec_xxx, MO_16, do_vaddwev_u_s) +-TRANS(xvaddwev_d_wu_w, LASX, gvec_xxx, MO_32, do_vaddwev_u_s) +-TRANS(xvaddwev_q_du_d, LASX, gvec_xxx, MO_64, do_vaddwev_u_s) +- +-static void gen_vaddwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- +- /* Zero-extend the odd elements from a */ +- tcg_gen_shri_vec(vece, t1, a, halfbits); +- /* Sign-extend the odd elements from b */ +- tcg_gen_sari_vec(vece, t2, b, halfbits); +- +- tcg_gen_add_vec(vece, t, t1, t2); +-} +- +-static void gen_vaddwod_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_shri_i32(t1, a, 16); +- tcg_gen_sari_i32(t2, b, 16); +- tcg_gen_add_i32(t, t1, t2); +-} +- +-static void gen_vaddwod_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_shri_i64(t1, a, 32); +- tcg_gen_sari_i64(t2, b, 32); +- tcg_gen_add_i64(t, t1, t2); +-} +- +-static void do_vaddwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shri_vec, INDEX_op_sari_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vaddwod_u_s, +- .fno = gen_helper_vaddwod_h_bu_b, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vaddwod_w_hu_h, +- .fniv = gen_vaddwod_u_s, +- .fno = gen_helper_vaddwod_w_hu_h, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vaddwod_d_wu_w, +- .fniv = gen_vaddwod_u_s, +- .fno = gen_helper_vaddwod_d_wu_w, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- { +- .fno = gen_helper_vaddwod_q_du_d, +- .vece = MO_128 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vaddwod_h_bu_b, LSX, gvec_vvv, MO_8, do_vaddwod_u_s) +-TRANS(vaddwod_w_hu_h, LSX, gvec_vvv, MO_16, do_vaddwod_u_s) +-TRANS(vaddwod_d_wu_w, LSX, gvec_vvv, MO_32, do_vaddwod_u_s) +-TRANS(vaddwod_q_du_d, LSX, gvec_vvv, MO_64, do_vaddwod_u_s) +-TRANS(xvaddwod_h_bu_b, LSX, gvec_xxx, MO_8, do_vaddwod_u_s) +-TRANS(xvaddwod_w_hu_h, LSX, gvec_xxx, MO_16, do_vaddwod_u_s) +-TRANS(xvaddwod_d_wu_w, LSX, gvec_xxx, MO_32, do_vaddwod_u_s) +-TRANS(xvaddwod_q_du_d, LSX, gvec_xxx, MO_64, do_vaddwod_u_s) +- +-static void do_vavg(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, +- void (*gen_shr_vec)(unsigned, TCGv_vec, +- TCGv_vec, int64_t), +- void (*gen_round_vec)(unsigned, TCGv_vec, +- TCGv_vec, TCGv_vec)) +-{ +- TCGv_vec tmp = tcg_temp_new_vec_matching(t); +- gen_round_vec(vece, tmp, a, b); +- tcg_gen_and_vec(vece, tmp, tmp, tcg_constant_vec_matching(t, vece, 1)); +- gen_shr_vec(vece, a, a, 1); +- gen_shr_vec(vece, b, b, 1); +- tcg_gen_add_vec(vece, t, a, b); +- tcg_gen_add_vec(vece, t, t, tmp); +-} +- +-static void gen_vavg_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- do_vavg(vece, t, a, b, tcg_gen_sari_vec, tcg_gen_and_vec); +-} +- +-static void gen_vavg_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- do_vavg(vece, t, a, b, tcg_gen_shri_vec, tcg_gen_and_vec); +-} +- +-static void gen_vavgr_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- do_vavg(vece, t, a, b, tcg_gen_sari_vec, tcg_gen_or_vec); +-} +- +-static void gen_vavgr_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- do_vavg(vece, t, a, b, tcg_gen_shri_vec, tcg_gen_or_vec); +-} +- +-static void do_vavg_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_sari_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vavg_s, +- .fno = gen_helper_vavg_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vavg_s, +- .fno = gen_helper_vavg_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vavg_s, +- .fno = gen_helper_vavg_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vavg_s, +- .fno = gen_helper_vavg_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-static void do_vavg_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shri_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vavg_u, +- .fno = gen_helper_vavg_bu, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vavg_u, +- .fno = gen_helper_vavg_hu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vavg_u, +- .fno = gen_helper_vavg_wu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vavg_u, +- .fno = gen_helper_vavg_du, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vavg_b, LSX, gvec_vvv, MO_8, do_vavg_s) +-TRANS(vavg_h, LSX, gvec_vvv, MO_16, do_vavg_s) +-TRANS(vavg_w, LSX, gvec_vvv, MO_32, do_vavg_s) +-TRANS(vavg_d, LSX, gvec_vvv, MO_64, do_vavg_s) +-TRANS(vavg_bu, LSX, gvec_vvv, MO_8, do_vavg_u) +-TRANS(vavg_hu, LSX, gvec_vvv, MO_16, do_vavg_u) +-TRANS(vavg_wu, LSX, gvec_vvv, MO_32, do_vavg_u) +-TRANS(vavg_du, LSX, gvec_vvv, MO_64, do_vavg_u) +-TRANS(xvavg_b, LASX, gvec_xxx, MO_8, do_vavg_s) +-TRANS(xvavg_h, LASX, gvec_xxx, MO_16, do_vavg_s) +-TRANS(xvavg_w, LASX, gvec_xxx, MO_32, do_vavg_s) +-TRANS(xvavg_d, LASX, gvec_xxx, MO_64, do_vavg_s) +-TRANS(xvavg_bu, LASX, gvec_xxx, MO_8, do_vavg_u) +-TRANS(xvavg_hu, LASX, gvec_xxx, MO_16, do_vavg_u) +-TRANS(xvavg_wu, LASX, gvec_xxx, MO_32, do_vavg_u) +-TRANS(xvavg_du, LASX, gvec_xxx, MO_64, do_vavg_u) +- +-static void do_vavgr_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_sari_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vavgr_s, +- .fno = gen_helper_vavgr_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vavgr_s, +- .fno = gen_helper_vavgr_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vavgr_s, +- .fno = gen_helper_vavgr_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vavgr_s, +- .fno = gen_helper_vavgr_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-static void do_vavgr_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shri_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vavgr_u, +- .fno = gen_helper_vavgr_bu, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vavgr_u, +- .fno = gen_helper_vavgr_hu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vavgr_u, +- .fno = gen_helper_vavgr_wu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vavgr_u, +- .fno = gen_helper_vavgr_du, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vavgr_b, LSX, gvec_vvv, MO_8, do_vavgr_s) +-TRANS(vavgr_h, LSX, gvec_vvv, MO_16, do_vavgr_s) +-TRANS(vavgr_w, LSX, gvec_vvv, MO_32, do_vavgr_s) +-TRANS(vavgr_d, LSX, gvec_vvv, MO_64, do_vavgr_s) +-TRANS(vavgr_bu, LSX, gvec_vvv, MO_8, do_vavgr_u) +-TRANS(vavgr_hu, LSX, gvec_vvv, MO_16, do_vavgr_u) +-TRANS(vavgr_wu, LSX, gvec_vvv, MO_32, do_vavgr_u) +-TRANS(vavgr_du, LSX, gvec_vvv, MO_64, do_vavgr_u) +-TRANS(xvavgr_b, LASX, gvec_xxx, MO_8, do_vavgr_s) +-TRANS(xvavgr_h, LASX, gvec_xxx, MO_16, do_vavgr_s) +-TRANS(xvavgr_w, LASX, gvec_xxx, MO_32, do_vavgr_s) +-TRANS(xvavgr_d, LASX, gvec_xxx, MO_64, do_vavgr_s) +-TRANS(xvavgr_bu, LASX, gvec_xxx, MO_8, do_vavgr_u) +-TRANS(xvavgr_hu, LASX, gvec_xxx, MO_16, do_vavgr_u) +-TRANS(xvavgr_wu, LASX, gvec_xxx, MO_32, do_vavgr_u) +-TRANS(xvavgr_du, LASX, gvec_xxx, MO_64, do_vavgr_u) +- +-static void gen_vabsd_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- tcg_gen_smax_vec(vece, t, a, b); +- tcg_gen_smin_vec(vece, a, a, b); +- tcg_gen_sub_vec(vece, t, t, a); +-} +- +-static void do_vabsd_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_smax_vec, INDEX_op_smin_vec, INDEX_op_sub_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vabsd_s, +- .fno = gen_helper_vabsd_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vabsd_s, +- .fno = gen_helper_vabsd_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vabsd_s, +- .fno = gen_helper_vabsd_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vabsd_s, +- .fno = gen_helper_vabsd_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-static void gen_vabsd_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- tcg_gen_umax_vec(vece, t, a, b); +- tcg_gen_umin_vec(vece, a, a, b); +- tcg_gen_sub_vec(vece, t, t, a); +-} +- +-static void do_vabsd_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_umax_vec, INDEX_op_umin_vec, INDEX_op_sub_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vabsd_u, +- .fno = gen_helper_vabsd_bu, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vabsd_u, +- .fno = gen_helper_vabsd_hu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vabsd_u, +- .fno = gen_helper_vabsd_wu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vabsd_u, +- .fno = gen_helper_vabsd_du, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vabsd_b, LSX, gvec_vvv, MO_8, do_vabsd_s) +-TRANS(vabsd_h, LSX, gvec_vvv, MO_16, do_vabsd_s) +-TRANS(vabsd_w, LSX, gvec_vvv, MO_32, do_vabsd_s) +-TRANS(vabsd_d, LSX, gvec_vvv, MO_64, do_vabsd_s) +-TRANS(vabsd_bu, LSX, gvec_vvv, MO_8, do_vabsd_u) +-TRANS(vabsd_hu, LSX, gvec_vvv, MO_16, do_vabsd_u) +-TRANS(vabsd_wu, LSX, gvec_vvv, MO_32, do_vabsd_u) +-TRANS(vabsd_du, LSX, gvec_vvv, MO_64, do_vabsd_u) +-TRANS(xvabsd_b, LASX, gvec_xxx, MO_8, do_vabsd_s) +-TRANS(xvabsd_h, LASX, gvec_xxx, MO_16, do_vabsd_s) +-TRANS(xvabsd_w, LASX, gvec_xxx, MO_32, do_vabsd_s) +-TRANS(xvabsd_d, LASX, gvec_xxx, MO_64, do_vabsd_s) +-TRANS(xvabsd_bu, LASX, gvec_xxx, MO_8, do_vabsd_u) +-TRANS(xvabsd_hu, LASX, gvec_xxx, MO_16, do_vabsd_u) +-TRANS(xvabsd_wu, LASX, gvec_xxx, MO_32, do_vabsd_u) +-TRANS(xvabsd_du, LASX, gvec_xxx, MO_64, do_vabsd_u) +- +-static void gen_vadda(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- +- tcg_gen_abs_vec(vece, t1, a); +- tcg_gen_abs_vec(vece, t2, b); +- tcg_gen_add_vec(vece, t, t1, t2); +-} +- +-static void do_vadda(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_abs_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vadda, +- .fno = gen_helper_vadda_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vadda, +- .fno = gen_helper_vadda_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vadda, +- .fno = gen_helper_vadda_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vadda, +- .fno = gen_helper_vadda_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vadda_b, LSX, gvec_vvv, MO_8, do_vadda) +-TRANS(vadda_h, LSX, gvec_vvv, MO_16, do_vadda) +-TRANS(vadda_w, LSX, gvec_vvv, MO_32, do_vadda) +-TRANS(vadda_d, LSX, gvec_vvv, MO_64, do_vadda) +-TRANS(xvadda_b, LASX, gvec_xxx, MO_8, do_vadda) +-TRANS(xvadda_h, LASX, gvec_xxx, MO_16, do_vadda) +-TRANS(xvadda_w, LASX, gvec_xxx, MO_32, do_vadda) +-TRANS(xvadda_d, LASX, gvec_xxx, MO_64, do_vadda) +- +-TRANS(vmax_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_smax) +-TRANS(vmax_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_smax) +-TRANS(vmax_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_smax) +-TRANS(vmax_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_smax) +-TRANS(vmax_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_umax) +-TRANS(vmax_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_umax) +-TRANS(vmax_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_umax) +-TRANS(vmax_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_umax) +-TRANS(xvmax_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_smax) +-TRANS(xvmax_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_smax) +-TRANS(xvmax_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_smax) +-TRANS(xvmax_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_smax) +-TRANS(xvmax_bu, LASX, gvec_xxx, MO_8, tcg_gen_gvec_umax) +-TRANS(xvmax_hu, LASX, gvec_xxx, MO_16, tcg_gen_gvec_umax) +-TRANS(xvmax_wu, LASX, gvec_xxx, MO_32, tcg_gen_gvec_umax) +-TRANS(xvmax_du, LASX, gvec_xxx, MO_64, tcg_gen_gvec_umax) +- +-TRANS(vmin_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_smin) +-TRANS(vmin_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_smin) +-TRANS(vmin_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_smin) +-TRANS(vmin_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_smin) +-TRANS(vmin_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_umin) +-TRANS(vmin_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_umin) +-TRANS(vmin_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_umin) +-TRANS(vmin_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_umin) +-TRANS(xvmin_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_smin) +-TRANS(xvmin_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_smin) +-TRANS(xvmin_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_smin) +-TRANS(xvmin_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_smin) +-TRANS(xvmin_bu, LASX, gvec_xxx, MO_8, tcg_gen_gvec_umin) +-TRANS(xvmin_hu, LASX, gvec_xxx, MO_16, tcg_gen_gvec_umin) +-TRANS(xvmin_wu, LASX, gvec_xxx, MO_32, tcg_gen_gvec_umin) +-TRANS(xvmin_du, LASX, gvec_xxx, MO_64, tcg_gen_gvec_umin) +- +-static void gen_vmini_s(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) +-{ +- tcg_gen_smin_vec(vece, t, a, tcg_constant_vec_matching(t, vece, imm)); +-} +- +-static void gen_vmini_u(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) +-{ +- tcg_gen_umin_vec(vece, t, a, tcg_constant_vec_matching(t, vece, imm)); +-} +- +-static void gen_vmaxi_s(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) +-{ +- tcg_gen_smax_vec(vece, t, a, tcg_constant_vec_matching(t, vece, imm)); +-} +- +-static void gen_vmaxi_u(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) +-{ +- tcg_gen_umax_vec(vece, t, a, tcg_constant_vec_matching(t, vece, imm)); +-} +- +-static void do_vmini_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- int64_t imm, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_smin_vec, 0 +- }; +- static const GVecGen2i op[4] = { +- { +- .fniv = gen_vmini_s, +- .fnoi = gen_helper_vmini_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vmini_s, +- .fnoi = gen_helper_vmini_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vmini_s, +- .fnoi = gen_helper_vmini_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vmini_s, +- .fnoi = gen_helper_vmini_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); +-} +- +-static void do_vmini_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- int64_t imm, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_umin_vec, 0 +- }; +- static const GVecGen2i op[4] = { +- { +- .fniv = gen_vmini_u, +- .fnoi = gen_helper_vmini_bu, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vmini_u, +- .fnoi = gen_helper_vmini_hu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vmini_u, +- .fnoi = gen_helper_vmini_wu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vmini_u, +- .fnoi = gen_helper_vmini_du, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); +-} +- +-TRANS(vmini_b, LSX, gvec_vv_i, MO_8, do_vmini_s) +-TRANS(vmini_h, LSX, gvec_vv_i, MO_16, do_vmini_s) +-TRANS(vmini_w, LSX, gvec_vv_i, MO_32, do_vmini_s) +-TRANS(vmini_d, LSX, gvec_vv_i, MO_64, do_vmini_s) +-TRANS(vmini_bu, LSX, gvec_vv_i, MO_8, do_vmini_u) +-TRANS(vmini_hu, LSX, gvec_vv_i, MO_16, do_vmini_u) +-TRANS(vmini_wu, LSX, gvec_vv_i, MO_32, do_vmini_u) +-TRANS(vmini_du, LSX, gvec_vv_i, MO_64, do_vmini_u) +-TRANS(xvmini_b, LASX, gvec_xx_i, MO_8, do_vmini_s) +-TRANS(xvmini_h, LASX, gvec_xx_i, MO_16, do_vmini_s) +-TRANS(xvmini_w, LASX, gvec_xx_i, MO_32, do_vmini_s) +-TRANS(xvmini_d, LASX, gvec_xx_i, MO_64, do_vmini_s) +-TRANS(xvmini_bu, LASX, gvec_xx_i, MO_8, do_vmini_u) +-TRANS(xvmini_hu, LASX, gvec_xx_i, MO_16, do_vmini_u) +-TRANS(xvmini_wu, LASX, gvec_xx_i, MO_32, do_vmini_u) +-TRANS(xvmini_du, LASX, gvec_xx_i, MO_64, do_vmini_u) +- +-static void do_vmaxi_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- int64_t imm, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_smax_vec, 0 +- }; +- static const GVecGen2i op[4] = { +- { +- .fniv = gen_vmaxi_s, +- .fnoi = gen_helper_vmaxi_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vmaxi_s, +- .fnoi = gen_helper_vmaxi_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vmaxi_s, +- .fnoi = gen_helper_vmaxi_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vmaxi_s, +- .fnoi = gen_helper_vmaxi_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); +-} +- +-static void do_vmaxi_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- int64_t imm, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_umax_vec, 0 +- }; +- static const GVecGen2i op[4] = { +- { +- .fniv = gen_vmaxi_u, +- .fnoi = gen_helper_vmaxi_bu, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vmaxi_u, +- .fnoi = gen_helper_vmaxi_hu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vmaxi_u, +- .fnoi = gen_helper_vmaxi_wu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vmaxi_u, +- .fnoi = gen_helper_vmaxi_du, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); +-} +- +-TRANS(vmaxi_b, LSX, gvec_vv_i, MO_8, do_vmaxi_s) +-TRANS(vmaxi_h, LSX, gvec_vv_i, MO_16, do_vmaxi_s) +-TRANS(vmaxi_w, LSX, gvec_vv_i, MO_32, do_vmaxi_s) +-TRANS(vmaxi_d, LSX, gvec_vv_i, MO_64, do_vmaxi_s) +-TRANS(vmaxi_bu, LSX, gvec_vv_i, MO_8, do_vmaxi_u) +-TRANS(vmaxi_hu, LSX, gvec_vv_i, MO_16, do_vmaxi_u) +-TRANS(vmaxi_wu, LSX, gvec_vv_i, MO_32, do_vmaxi_u) +-TRANS(vmaxi_du, LSX, gvec_vv_i, MO_64, do_vmaxi_u) +-TRANS(xvmaxi_b, LASX, gvec_xx_i, MO_8, do_vmaxi_s) +-TRANS(xvmaxi_h, LASX, gvec_xx_i, MO_16, do_vmaxi_s) +-TRANS(xvmaxi_w, LASX, gvec_xx_i, MO_32, do_vmaxi_s) +-TRANS(xvmaxi_d, LASX, gvec_xx_i, MO_64, do_vmaxi_s) +-TRANS(xvmaxi_bu, LASX, gvec_xx_i, MO_8, do_vmaxi_u) +-TRANS(xvmaxi_hu, LASX, gvec_xx_i, MO_16, do_vmaxi_u) +-TRANS(xvmaxi_wu, LASX, gvec_xx_i, MO_32, do_vmaxi_u) +-TRANS(xvmaxi_du, LASX, gvec_xx_i, MO_64, do_vmaxi_u) +- +-TRANS(vmul_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_mul) +-TRANS(vmul_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_mul) +-TRANS(vmul_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_mul) +-TRANS(vmul_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_mul) +-TRANS(xvmul_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_mul) +-TRANS(xvmul_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_mul) +-TRANS(xvmul_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_mul) +-TRANS(xvmul_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_mul) +- +-static void gen_vmuh_w(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 discard = tcg_temp_new_i32(); +- tcg_gen_muls2_i32(discard, t, a, b); +-} +- +-static void gen_vmuh_d(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 discard = tcg_temp_new_i64(); +- tcg_gen_muls2_i64(discard, t, a, b); +-} +- +-static void do_vmuh_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const GVecGen3 op[4] = { +- { +- .fno = gen_helper_vmuh_b, +- .vece = MO_8 +- }, +- { +- .fno = gen_helper_vmuh_h, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmuh_w, +- .fno = gen_helper_vmuh_w, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmuh_d, +- .fno = gen_helper_vmuh_d, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmuh_b, LSX, gvec_vvv, MO_8, do_vmuh_s) +-TRANS(vmuh_h, LSX, gvec_vvv, MO_16, do_vmuh_s) +-TRANS(vmuh_w, LSX, gvec_vvv, MO_32, do_vmuh_s) +-TRANS(vmuh_d, LSX, gvec_vvv, MO_64, do_vmuh_s) +-TRANS(xvmuh_b, LASX, gvec_xxx, MO_8, do_vmuh_s) +-TRANS(xvmuh_h, LASX, gvec_xxx, MO_16, do_vmuh_s) +-TRANS(xvmuh_w, LASX, gvec_xxx, MO_32, do_vmuh_s) +-TRANS(xvmuh_d, LASX, gvec_xxx, MO_64, do_vmuh_s) +- +-static void gen_vmuh_wu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 discard = tcg_temp_new_i32(); +- tcg_gen_mulu2_i32(discard, t, a, b); +-} +- +-static void gen_vmuh_du(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 discard = tcg_temp_new_i64(); +- tcg_gen_mulu2_i64(discard, t, a, b); +-} +- +-static void do_vmuh_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const GVecGen3 op[4] = { +- { +- .fno = gen_helper_vmuh_bu, +- .vece = MO_8 +- }, +- { +- .fno = gen_helper_vmuh_hu, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmuh_wu, +- .fno = gen_helper_vmuh_wu, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmuh_du, +- .fno = gen_helper_vmuh_du, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmuh_bu, LSX, gvec_vvv, MO_8, do_vmuh_u) +-TRANS(vmuh_hu, LSX, gvec_vvv, MO_16, do_vmuh_u) +-TRANS(vmuh_wu, LSX, gvec_vvv, MO_32, do_vmuh_u) +-TRANS(vmuh_du, LSX, gvec_vvv, MO_64, do_vmuh_u) +-TRANS(xvmuh_bu, LASX, gvec_xxx, MO_8, do_vmuh_u) +-TRANS(xvmuh_hu, LASX, gvec_xxx, MO_16, do_vmuh_u) +-TRANS(xvmuh_wu, LASX, gvec_xxx, MO_32, do_vmuh_u) +-TRANS(xvmuh_du, LASX, gvec_xxx, MO_64, do_vmuh_u) +- +-static void gen_vmulwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- tcg_gen_shli_vec(vece, t1, a, halfbits); +- tcg_gen_sari_vec(vece, t1, t1, halfbits); +- tcg_gen_shli_vec(vece, t2, b, halfbits); +- tcg_gen_sari_vec(vece, t2, t2, halfbits); +- tcg_gen_mul_vec(vece, t, t1, t2); +-} +- +-static void gen_vmulwev_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_ext16s_i32(t1, a); +- tcg_gen_ext16s_i32(t2, b); +- tcg_gen_mul_i32(t, t1, t2); +-} +- +-static void gen_vmulwev_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_ext32s_i64(t1, a); +- tcg_gen_ext32s_i64(t2, b); +- tcg_gen_mul_i64(t, t1, t2); +-} +- +-static void do_vmulwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shli_vec, INDEX_op_sari_vec, INDEX_op_mul_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmulwev_s, +- .fno = gen_helper_vmulwev_h_b, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmulwev_w_h, +- .fniv = gen_vmulwev_s, +- .fno = gen_helper_vmulwev_w_h, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmulwev_d_w, +- .fniv = gen_vmulwev_s, +- .fno = gen_helper_vmulwev_d_w, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmulwev_h_b, LSX, gvec_vvv, MO_8, do_vmulwev_s) +-TRANS(vmulwev_w_h, LSX, gvec_vvv, MO_16, do_vmulwev_s) +-TRANS(vmulwev_d_w, LSX, gvec_vvv, MO_32, do_vmulwev_s) +-TRANS(xvmulwev_h_b, LASX, gvec_xxx, MO_8, do_vmulwev_s) +-TRANS(xvmulwev_w_h, LASX, gvec_xxx, MO_16, do_vmulwev_s) +-TRANS(xvmulwev_d_w, LASX, gvec_xxx, MO_32, do_vmulwev_s) +- +-static void tcg_gen_mulus2_i64(TCGv_i64 rl, TCGv_i64 rh, +- TCGv_i64 arg1, TCGv_i64 arg2) +-{ +- tcg_gen_mulsu2_i64(rl, rh, arg2, arg1); +-} +- +-static bool gen_vmul_q_vl(DisasContext *ctx, +- arg_vvv *a, uint32_t oprsz, int idx1, int idx2, +- void (*func)(TCGv_i64, TCGv_i64, +- TCGv_i64, TCGv_i64)) +-{ +- TCGv_i64 rh, rl, arg1, arg2; +- int i; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- rh = tcg_temp_new_i64(); +- rl = tcg_temp_new_i64(); +- arg1 = tcg_temp_new_i64(); +- arg2 = tcg_temp_new_i64(); +- +- for (i = 0; i < oprsz / 16; i++) { +- get_vreg64(arg1, a->vj, 2 * i + idx1); +- get_vreg64(arg2, a->vk, 2 * i + idx2); +- +- func(rl, rh, arg1, arg2); +- +- set_vreg64(rh, a->vd, 2 * i + 1); +- set_vreg64(rl, a->vd, 2 * i); +- } +- +- return true; +-} +- +-static bool gen_vmul_q(DisasContext *ctx, arg_vvv *a, int idx1, int idx2, +- void (*func)(TCGv_i64, TCGv_i64, +- TCGv_i64, TCGv_i64)) +-{ +- return gen_vmul_q_vl(ctx, a, 16, idx1, idx2, func); +-} +- +-static bool gen_xvmul_q(DisasContext *ctx, arg_vvv *a, int idx1, int idx2, +- void (*func)(TCGv_i64, TCGv_i64, +- TCGv_i64, TCGv_i64)) +-{ +- return gen_vmul_q_vl(ctx, a, 32, idx1, idx2, func); +-} +- +-TRANS(vmulwev_q_d, LSX, gen_vmul_q, 0, 0, tcg_gen_muls2_i64) +-TRANS(vmulwod_q_d, LSX, gen_vmul_q, 1, 1, tcg_gen_muls2_i64) +-TRANS(vmulwev_q_du, LSX, gen_vmul_q, 0, 0, tcg_gen_mulu2_i64) +-TRANS(vmulwod_q_du, LSX, gen_vmul_q, 1, 1, tcg_gen_mulu2_i64) +-TRANS(vmulwev_q_du_d, LSX, gen_vmul_q, 0, 0, tcg_gen_mulus2_i64) +-TRANS(vmulwod_q_du_d, LSX, gen_vmul_q, 1, 1, tcg_gen_mulus2_i64) +-TRANS(xvmulwev_q_d, LASX, gen_xvmul_q, 0, 0, tcg_gen_muls2_i64) +-TRANS(xvmulwod_q_d, LASX, gen_xvmul_q, 1, 1, tcg_gen_muls2_i64) +-TRANS(xvmulwev_q_du, LASX, gen_xvmul_q, 0, 0, tcg_gen_mulu2_i64) +-TRANS(xvmulwod_q_du, LASX, gen_xvmul_q, 1, 1, tcg_gen_mulu2_i64) +-TRANS(xvmulwev_q_du_d, LASX, gen_xvmul_q, 0, 0, tcg_gen_mulus2_i64) +-TRANS(xvmulwod_q_du_d, LASX, gen_xvmul_q, 1, 1, tcg_gen_mulus2_i64) +- +-static void gen_vmulwod_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- tcg_gen_sari_vec(vece, t1, a, halfbits); +- tcg_gen_sari_vec(vece, t2, b, halfbits); +- tcg_gen_mul_vec(vece, t, t1, t2); +-} +- +-static void gen_vmulwod_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_sari_i32(t1, a, 16); +- tcg_gen_sari_i32(t2, b, 16); +- tcg_gen_mul_i32(t, t1, t2); +-} +- +-static void gen_vmulwod_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_sari_i64(t1, a, 32); +- tcg_gen_sari_i64(t2, b, 32); +- tcg_gen_mul_i64(t, t1, t2); +-} +- +-static void do_vmulwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_sari_vec, INDEX_op_mul_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmulwod_s, +- .fno = gen_helper_vmulwod_h_b, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmulwod_w_h, +- .fniv = gen_vmulwod_s, +- .fno = gen_helper_vmulwod_w_h, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmulwod_d_w, +- .fniv = gen_vmulwod_s, +- .fno = gen_helper_vmulwod_d_w, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmulwod_h_b, LSX, gvec_vvv, MO_8, do_vmulwod_s) +-TRANS(vmulwod_w_h, LSX, gvec_vvv, MO_16, do_vmulwod_s) +-TRANS(vmulwod_d_w, LSX, gvec_vvv, MO_32, do_vmulwod_s) +-TRANS(xvmulwod_h_b, LASX, gvec_xxx, MO_8, do_vmulwod_s) +-TRANS(xvmulwod_w_h, LASX, gvec_xxx, MO_16, do_vmulwod_s) +-TRANS(xvmulwod_d_w, LASX, gvec_xxx, MO_32, do_vmulwod_s) +- +-static void gen_vmulwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, mask; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- mask = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); +- tcg_gen_and_vec(vece, t1, a, mask); +- tcg_gen_and_vec(vece, t2, b, mask); +- tcg_gen_mul_vec(vece, t, t1, t2); +-} +- +-static void gen_vmulwev_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_ext16u_i32(t1, a); +- tcg_gen_ext16u_i32(t2, b); +- tcg_gen_mul_i32(t, t1, t2); +-} +- +-static void gen_vmulwev_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_ext32u_i64(t1, a); +- tcg_gen_ext32u_i64(t2, b); +- tcg_gen_mul_i64(t, t1, t2); +-} +- +-static void do_vmulwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_mul_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmulwev_u, +- .fno = gen_helper_vmulwev_h_bu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmulwev_w_hu, +- .fniv = gen_vmulwev_u, +- .fno = gen_helper_vmulwev_w_hu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmulwev_d_wu, +- .fniv = gen_vmulwev_u, +- .fno = gen_helper_vmulwev_d_wu, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmulwev_h_bu, LSX, gvec_vvv, MO_8, do_vmulwev_u) +-TRANS(vmulwev_w_hu, LSX, gvec_vvv, MO_16, do_vmulwev_u) +-TRANS(vmulwev_d_wu, LSX, gvec_vvv, MO_32, do_vmulwev_u) +-TRANS(xvmulwev_h_bu, LASX, gvec_xxx, MO_8, do_vmulwev_u) +-TRANS(xvmulwev_w_hu, LASX, gvec_xxx, MO_16, do_vmulwev_u) +-TRANS(xvmulwev_d_wu, LASX, gvec_xxx, MO_32, do_vmulwev_u) +- +-static void gen_vmulwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- tcg_gen_shri_vec(vece, t1, a, halfbits); +- tcg_gen_shri_vec(vece, t2, b, halfbits); +- tcg_gen_mul_vec(vece, t, t1, t2); +-} +- +-static void gen_vmulwod_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_shri_i32(t1, a, 16); +- tcg_gen_shri_i32(t2, b, 16); +- tcg_gen_mul_i32(t, t1, t2); +-} +- +-static void gen_vmulwod_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_shri_i64(t1, a, 32); +- tcg_gen_shri_i64(t2, b, 32); +- tcg_gen_mul_i64(t, t1, t2); +-} +- +-static void do_vmulwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shri_vec, INDEX_op_mul_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmulwod_u, +- .fno = gen_helper_vmulwod_h_bu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmulwod_w_hu, +- .fniv = gen_vmulwod_u, +- .fno = gen_helper_vmulwod_w_hu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmulwod_d_wu, +- .fniv = gen_vmulwod_u, +- .fno = gen_helper_vmulwod_d_wu, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmulwod_h_bu, LSX, gvec_vvv, MO_8, do_vmulwod_u) +-TRANS(vmulwod_w_hu, LSX, gvec_vvv, MO_16, do_vmulwod_u) +-TRANS(vmulwod_d_wu, LSX, gvec_vvv, MO_32, do_vmulwod_u) +-TRANS(xvmulwod_h_bu, LASX, gvec_xxx, MO_8, do_vmulwod_u) +-TRANS(xvmulwod_w_hu, LASX, gvec_xxx, MO_16, do_vmulwod_u) +-TRANS(xvmulwod_d_wu, LASX, gvec_xxx, MO_32, do_vmulwod_u) +- +-static void gen_vmulwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, mask; +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- mask = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); +- tcg_gen_and_vec(vece, t1, a, mask); +- tcg_gen_shli_vec(vece, t2, b, halfbits); +- tcg_gen_sari_vec(vece, t2, t2, halfbits); +- tcg_gen_mul_vec(vece, t, t1, t2); +-} +- +-static void gen_vmulwev_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_ext16u_i32(t1, a); +- tcg_gen_ext16s_i32(t2, b); +- tcg_gen_mul_i32(t, t1, t2); +-} +- +-static void gen_vmulwev_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_ext32u_i64(t1, a); +- tcg_gen_ext32s_i64(t2, b); +- tcg_gen_mul_i64(t, t1, t2); +-} +- +-static void do_vmulwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shli_vec, INDEX_op_sari_vec, INDEX_op_mul_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmulwev_u_s, +- .fno = gen_helper_vmulwev_h_bu_b, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmulwev_w_hu_h, +- .fniv = gen_vmulwev_u_s, +- .fno = gen_helper_vmulwev_w_hu_h, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmulwev_d_wu_w, +- .fniv = gen_vmulwev_u_s, +- .fno = gen_helper_vmulwev_d_wu_w, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmulwev_h_bu_b, LSX, gvec_vvv, MO_8, do_vmulwev_u_s) +-TRANS(vmulwev_w_hu_h, LSX, gvec_vvv, MO_16, do_vmulwev_u_s) +-TRANS(vmulwev_d_wu_w, LSX, gvec_vvv, MO_32, do_vmulwev_u_s) +-TRANS(xvmulwev_h_bu_b, LASX, gvec_xxx, MO_8, do_vmulwev_u_s) +-TRANS(xvmulwev_w_hu_h, LASX, gvec_xxx, MO_16, do_vmulwev_u_s) +-TRANS(xvmulwev_d_wu_w, LASX, gvec_xxx, MO_32, do_vmulwev_u_s) +- +-static void gen_vmulwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2; +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- tcg_gen_shri_vec(vece, t1, a, halfbits); +- tcg_gen_sari_vec(vece, t2, b, halfbits); +- tcg_gen_mul_vec(vece, t, t1, t2); +-} +- +-static void gen_vmulwod_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1, t2; +- +- t1 = tcg_temp_new_i32(); +- t2 = tcg_temp_new_i32(); +- tcg_gen_shri_i32(t1, a, 16); +- tcg_gen_sari_i32(t2, b, 16); +- tcg_gen_mul_i32(t, t1, t2); +-} +-static void gen_vmulwod_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1, t2; +- +- t1 = tcg_temp_new_i64(); +- t2 = tcg_temp_new_i64(); +- tcg_gen_shri_i64(t1, a, 32); +- tcg_gen_sari_i64(t2, b, 32); +- tcg_gen_mul_i64(t, t1, t2); +-} +- +-static void do_vmulwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shri_vec, INDEX_op_sari_vec, INDEX_op_mul_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmulwod_u_s, +- .fno = gen_helper_vmulwod_h_bu_b, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmulwod_w_hu_h, +- .fniv = gen_vmulwod_u_s, +- .fno = gen_helper_vmulwod_w_hu_h, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmulwod_d_wu_w, +- .fniv = gen_vmulwod_u_s, +- .fno = gen_helper_vmulwod_d_wu_w, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmulwod_h_bu_b, LSX, gvec_vvv, MO_8, do_vmulwod_u_s) +-TRANS(vmulwod_w_hu_h, LSX, gvec_vvv, MO_16, do_vmulwod_u_s) +-TRANS(vmulwod_d_wu_w, LSX, gvec_vvv, MO_32, do_vmulwod_u_s) +-TRANS(xvmulwod_h_bu_b, LASX, gvec_xxx, MO_8, do_vmulwod_u_s) +-TRANS(xvmulwod_w_hu_h, LASX, gvec_xxx, MO_16, do_vmulwod_u_s) +-TRANS(xvmulwod_d_wu_w, LASX, gvec_xxx, MO_32, do_vmulwod_u_s) +- +-static void gen_vmadd(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1; +- +- t1 = tcg_temp_new_vec_matching(t); +- tcg_gen_mul_vec(vece, t1, a, b); +- tcg_gen_add_vec(vece, t, t, t1); +-} +- +-static void gen_vmadd_w(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1; +- +- t1 = tcg_temp_new_i32(); +- tcg_gen_mul_i32(t1, a, b); +- tcg_gen_add_i32(t, t, t1); +-} +- +-static void gen_vmadd_d(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1; +- +- t1 = tcg_temp_new_i64(); +- tcg_gen_mul_i64(t1, a, b); +- tcg_gen_add_i64(t, t, t1); +-} +- +-static void do_vmadd(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_mul_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vmadd, +- .fno = gen_helper_vmadd_b, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vmadd, +- .fno = gen_helper_vmadd_h, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmadd_w, +- .fniv = gen_vmadd, +- .fno = gen_helper_vmadd_w, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmadd_d, +- .fniv = gen_vmadd, +- .fno = gen_helper_vmadd_d, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmadd_b, LSX, gvec_vvv, MO_8, do_vmadd) +-TRANS(vmadd_h, LSX, gvec_vvv, MO_16, do_vmadd) +-TRANS(vmadd_w, LSX, gvec_vvv, MO_32, do_vmadd) +-TRANS(vmadd_d, LSX, gvec_vvv, MO_64, do_vmadd) +-TRANS(xvmadd_b, LASX, gvec_xxx, MO_8, do_vmadd) +-TRANS(xvmadd_h, LASX, gvec_xxx, MO_16, do_vmadd) +-TRANS(xvmadd_w, LASX, gvec_xxx, MO_32, do_vmadd) +-TRANS(xvmadd_d, LASX, gvec_xxx, MO_64, do_vmadd) +- +-static void gen_vmsub(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1; +- +- t1 = tcg_temp_new_vec_matching(t); +- tcg_gen_mul_vec(vece, t1, a, b); +- tcg_gen_sub_vec(vece, t, t, t1); +-} +- +-static void gen_vmsub_w(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1; +- +- t1 = tcg_temp_new_i32(); +- tcg_gen_mul_i32(t1, a, b); +- tcg_gen_sub_i32(t, t, t1); +-} +- +-static void gen_vmsub_d(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1; +- +- t1 = tcg_temp_new_i64(); +- tcg_gen_mul_i64(t1, a, b); +- tcg_gen_sub_i64(t, t, t1); +-} +- +-static void do_vmsub(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_mul_vec, INDEX_op_sub_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vmsub, +- .fno = gen_helper_vmsub_b, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vmsub, +- .fno = gen_helper_vmsub_h, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmsub_w, +- .fniv = gen_vmsub, +- .fno = gen_helper_vmsub_w, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmsub_d, +- .fniv = gen_vmsub, +- .fno = gen_helper_vmsub_d, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmsub_b, LSX, gvec_vvv, MO_8, do_vmsub) +-TRANS(vmsub_h, LSX, gvec_vvv, MO_16, do_vmsub) +-TRANS(vmsub_w, LSX, gvec_vvv, MO_32, do_vmsub) +-TRANS(vmsub_d, LSX, gvec_vvv, MO_64, do_vmsub) +-TRANS(xvmsub_b, LASX, gvec_xxx, MO_8, do_vmsub) +-TRANS(xvmsub_h, LASX, gvec_xxx, MO_16, do_vmsub) +-TRANS(xvmsub_w, LASX, gvec_xxx, MO_32, do_vmsub) +-TRANS(xvmsub_d, LASX, gvec_xxx, MO_64, do_vmsub) +- +-static void gen_vmaddwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, t3; +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- t3 = tcg_temp_new_vec_matching(t); +- tcg_gen_shli_vec(vece, t1, a, halfbits); +- tcg_gen_sari_vec(vece, t1, t1, halfbits); +- tcg_gen_shli_vec(vece, t2, b, halfbits); +- tcg_gen_sari_vec(vece, t2, t2, halfbits); +- tcg_gen_mul_vec(vece, t3, t1, t2); +- tcg_gen_add_vec(vece, t, t, t3); +-} +- +-static void gen_vmaddwev_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1; +- +- t1 = tcg_temp_new_i32(); +- gen_vmulwev_w_h(t1, a, b); +- tcg_gen_add_i32(t, t, t1); +-} +- +-static void gen_vmaddwev_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1; +- +- t1 = tcg_temp_new_i64(); +- gen_vmulwev_d_w(t1, a, b); +- tcg_gen_add_i64(t, t, t1); +-} +- +-static void do_vmaddwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shli_vec, INDEX_op_sari_vec, +- INDEX_op_mul_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmaddwev_s, +- .fno = gen_helper_vmaddwev_h_b, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmaddwev_w_h, +- .fniv = gen_vmaddwev_s, +- .fno = gen_helper_vmaddwev_w_h, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmaddwev_d_w, +- .fniv = gen_vmaddwev_s, +- .fno = gen_helper_vmaddwev_d_w, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmaddwev_h_b, LSX, gvec_vvv, MO_8, do_vmaddwev_s) +-TRANS(vmaddwev_w_h, LSX, gvec_vvv, MO_16, do_vmaddwev_s) +-TRANS(vmaddwev_d_w, LSX, gvec_vvv, MO_32, do_vmaddwev_s) +-TRANS(xvmaddwev_h_b, LASX, gvec_xxx, MO_8, do_vmaddwev_s) +-TRANS(xvmaddwev_w_h, LASX, gvec_xxx, MO_16, do_vmaddwev_s) +-TRANS(xvmaddwev_d_w, LASX, gvec_xxx, MO_32, do_vmaddwev_s) +- +-static bool gen_vmadd_q_vl(DisasContext * ctx, +- arg_vvv *a, uint32_t oprsz, int idx1, int idx2, +- void (*func)(TCGv_i64, TCGv_i64, +- TCGv_i64, TCGv_i64)) +-{ +- TCGv_i64 rh, rl, arg1, arg2, th, tl; +- int i; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- rh = tcg_temp_new_i64(); +- rl = tcg_temp_new_i64(); +- arg1 = tcg_temp_new_i64(); +- arg2 = tcg_temp_new_i64(); +- th = tcg_temp_new_i64(); +- tl = tcg_temp_new_i64(); +- +- for (i = 0; i < oprsz / 16; i++) { +- get_vreg64(arg1, a->vj, 2 * i + idx1); +- get_vreg64(arg2, a->vk, 2 * i + idx2); +- get_vreg64(rh, a->vd, 2 * i + 1); +- get_vreg64(rl, a->vd, 2 * i); +- +- func(tl, th, arg1, arg2); +- tcg_gen_add2_i64(rl, rh, rl, rh, tl, th); +- +- set_vreg64(rh, a->vd, 2 * i + 1); +- set_vreg64(rl, a->vd, 2 * i); +- } +- +- return true; +-} +- +-static bool gen_vmadd_q(DisasContext *ctx, arg_vvv *a, int idx1, int idx2, +- void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) +-{ +- return gen_vmadd_q_vl(ctx, a, 16, idx1, idx2, func); +-} +- +-static bool gen_xvmadd_q(DisasContext *ctx, arg_vvv *a, int idx1, int idx2, +- void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) +-{ +- return gen_vmadd_q_vl(ctx, a, 32, idx1, idx2, func); +-} +- +-TRANS(vmaddwev_q_d, LSX, gen_vmadd_q, 0, 0, tcg_gen_muls2_i64) +-TRANS(vmaddwod_q_d, LSX, gen_vmadd_q, 1, 1, tcg_gen_muls2_i64) +-TRANS(vmaddwev_q_du, LSX, gen_vmadd_q, 0, 0, tcg_gen_mulu2_i64) +-TRANS(vmaddwod_q_du, LSX, gen_vmadd_q, 1, 1, tcg_gen_mulu2_i64) +-TRANS(vmaddwev_q_du_d, LSX, gen_vmadd_q, 0, 0, tcg_gen_mulus2_i64) +-TRANS(vmaddwod_q_du_d, LSX, gen_vmadd_q, 1, 1, tcg_gen_mulus2_i64) +-TRANS(xvmaddwev_q_d, LASX, gen_xvmadd_q, 0, 0, tcg_gen_muls2_i64) +-TRANS(xvmaddwod_q_d, LASX, gen_xvmadd_q, 1, 1, tcg_gen_muls2_i64) +-TRANS(xvmaddwev_q_du, LASX, gen_xvmadd_q, 0, 0, tcg_gen_mulu2_i64) +-TRANS(xvmaddwod_q_du, LASX, gen_xvmadd_q, 1, 1, tcg_gen_mulu2_i64) +-TRANS(xvmaddwev_q_du_d, LASX, gen_xvmadd_q, 0, 0, tcg_gen_mulus2_i64) +-TRANS(xvmaddwod_q_du_d, LASX, gen_xvmadd_q, 1, 1, tcg_gen_mulus2_i64) +- +-static void gen_vmaddwod_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, t3; +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- t3 = tcg_temp_new_vec_matching(t); +- tcg_gen_sari_vec(vece, t1, a, halfbits); +- tcg_gen_sari_vec(vece, t2, b, halfbits); +- tcg_gen_mul_vec(vece, t3, t1, t2); +- tcg_gen_add_vec(vece, t, t, t3); +-} +- +-static void gen_vmaddwod_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1; +- +- t1 = tcg_temp_new_i32(); +- gen_vmulwod_w_h(t1, a, b); +- tcg_gen_add_i32(t, t, t1); +-} +- +-static void gen_vmaddwod_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1; +- +- t1 = tcg_temp_new_i64(); +- gen_vmulwod_d_w(t1, a, b); +- tcg_gen_add_i64(t, t, t1); +-} +- +-static void do_vmaddwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_sari_vec, INDEX_op_mul_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmaddwod_s, +- .fno = gen_helper_vmaddwod_h_b, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmaddwod_w_h, +- .fniv = gen_vmaddwod_s, +- .fno = gen_helper_vmaddwod_w_h, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmaddwod_d_w, +- .fniv = gen_vmaddwod_s, +- .fno = gen_helper_vmaddwod_d_w, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmaddwod_h_b, LSX, gvec_vvv, MO_8, do_vmaddwod_s) +-TRANS(vmaddwod_w_h, LSX, gvec_vvv, MO_16, do_vmaddwod_s) +-TRANS(vmaddwod_d_w, LSX, gvec_vvv, MO_32, do_vmaddwod_s) +-TRANS(xvmaddwod_h_b, LASX, gvec_xxx, MO_8, do_vmaddwod_s) +-TRANS(xvmaddwod_w_h, LASX, gvec_xxx, MO_16, do_vmaddwod_s) +-TRANS(xvmaddwod_d_w, LASX, gvec_xxx, MO_32, do_vmaddwod_s) +- +-static void gen_vmaddwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, mask; +- +- t1 = tcg_temp_new_vec_matching(t); +- t2 = tcg_temp_new_vec_matching(b); +- mask = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); +- tcg_gen_and_vec(vece, t1, a, mask); +- tcg_gen_and_vec(vece, t2, b, mask); +- tcg_gen_mul_vec(vece, t1, t1, t2); +- tcg_gen_add_vec(vece, t, t, t1); +-} +- +-static void gen_vmaddwev_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1; +- +- t1 = tcg_temp_new_i32(); +- gen_vmulwev_w_hu(t1, a, b); +- tcg_gen_add_i32(t, t, t1); +-} +- +-static void gen_vmaddwev_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1; +- +- t1 = tcg_temp_new_i64(); +- gen_vmulwev_d_wu(t1, a, b); +- tcg_gen_add_i64(t, t, t1); +-} +- +-static void do_vmaddwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_mul_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmaddwev_u, +- .fno = gen_helper_vmaddwev_h_bu, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmaddwev_w_hu, +- .fniv = gen_vmaddwev_u, +- .fno = gen_helper_vmaddwev_w_hu, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmaddwev_d_wu, +- .fniv = gen_vmaddwev_u, +- .fno = gen_helper_vmaddwev_d_wu, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmaddwev_h_bu, LSX, gvec_vvv, MO_8, do_vmaddwev_u) +-TRANS(vmaddwev_w_hu, LSX, gvec_vvv, MO_16, do_vmaddwev_u) +-TRANS(vmaddwev_d_wu, LSX, gvec_vvv, MO_32, do_vmaddwev_u) +-TRANS(xvmaddwev_h_bu, LASX, gvec_xxx, MO_8, do_vmaddwev_u) +-TRANS(xvmaddwev_w_hu, LASX, gvec_xxx, MO_16, do_vmaddwev_u) +-TRANS(xvmaddwev_d_wu, LASX, gvec_xxx, MO_32, do_vmaddwev_u) +- +-static void gen_vmaddwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, t3; +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- t3 = tcg_temp_new_vec_matching(t); +- tcg_gen_shri_vec(vece, t1, a, halfbits); +- tcg_gen_shri_vec(vece, t2, b, halfbits); +- tcg_gen_mul_vec(vece, t3, t1, t2); +- tcg_gen_add_vec(vece, t, t, t3); +-} +- +-static void gen_vmaddwod_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1; +- +- t1 = tcg_temp_new_i32(); +- gen_vmulwod_w_hu(t1, a, b); +- tcg_gen_add_i32(t, t, t1); +-} +- +-static void gen_vmaddwod_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1; +- +- t1 = tcg_temp_new_i64(); +- gen_vmulwod_d_wu(t1, a, b); +- tcg_gen_add_i64(t, t, t1); +-} +- +-static void do_vmaddwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shri_vec, INDEX_op_mul_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmaddwod_u, +- .fno = gen_helper_vmaddwod_h_bu, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmaddwod_w_hu, +- .fniv = gen_vmaddwod_u, +- .fno = gen_helper_vmaddwod_w_hu, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmaddwod_d_wu, +- .fniv = gen_vmaddwod_u, +- .fno = gen_helper_vmaddwod_d_wu, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmaddwod_h_bu, LSX, gvec_vvv, MO_8, do_vmaddwod_u) +-TRANS(vmaddwod_w_hu, LSX, gvec_vvv, MO_16, do_vmaddwod_u) +-TRANS(vmaddwod_d_wu, LSX, gvec_vvv, MO_32, do_vmaddwod_u) +-TRANS(xvmaddwod_h_bu, LASX, gvec_xxx, MO_8, do_vmaddwod_u) +-TRANS(xvmaddwod_w_hu, LASX, gvec_xxx, MO_16, do_vmaddwod_u) +-TRANS(xvmaddwod_d_wu, LASX, gvec_xxx, MO_32, do_vmaddwod_u) +- +-static void gen_vmaddwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, mask; +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- mask = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); +- tcg_gen_and_vec(vece, t1, a, mask); +- tcg_gen_shli_vec(vece, t2, b, halfbits); +- tcg_gen_sari_vec(vece, t2, t2, halfbits); +- tcg_gen_mul_vec(vece, t1, t1, t2); +- tcg_gen_add_vec(vece, t, t, t1); +-} +- +-static void gen_vmaddwev_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1; +- +- t1 = tcg_temp_new_i32(); +- gen_vmulwev_w_hu_h(t1, a, b); +- tcg_gen_add_i32(t, t, t1); +-} +- +-static void gen_vmaddwev_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1; +- +- t1 = tcg_temp_new_i64(); +- gen_vmulwev_d_wu_w(t1, a, b); +- tcg_gen_add_i64(t, t, t1); +-} +- +-static void do_vmaddwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shli_vec, INDEX_op_sari_vec, +- INDEX_op_mul_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmaddwev_u_s, +- .fno = gen_helper_vmaddwev_h_bu_b, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmaddwev_w_hu_h, +- .fniv = gen_vmaddwev_u_s, +- .fno = gen_helper_vmaddwev_w_hu_h, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmaddwev_d_wu_w, +- .fniv = gen_vmaddwev_u_s, +- .fno = gen_helper_vmaddwev_d_wu_w, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmaddwev_h_bu_b, LSX, gvec_vvv, MO_8, do_vmaddwev_u_s) +-TRANS(vmaddwev_w_hu_h, LSX, gvec_vvv, MO_16, do_vmaddwev_u_s) +-TRANS(vmaddwev_d_wu_w, LSX, gvec_vvv, MO_32, do_vmaddwev_u_s) +-TRANS(xvmaddwev_h_bu_b, LASX, gvec_xxx, MO_8, do_vmaddwev_u_s) +-TRANS(xvmaddwev_w_hu_h, LASX, gvec_xxx, MO_16, do_vmaddwev_u_s) +-TRANS(xvmaddwev_d_wu_w, LASX, gvec_xxx, MO_32, do_vmaddwev_u_s) +- +-static void gen_vmaddwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, t2, t3; +- int halfbits = 4 << vece; +- +- t1 = tcg_temp_new_vec_matching(a); +- t2 = tcg_temp_new_vec_matching(b); +- t3 = tcg_temp_new_vec_matching(t); +- tcg_gen_shri_vec(vece, t1, a, halfbits); +- tcg_gen_sari_vec(vece, t2, b, halfbits); +- tcg_gen_mul_vec(vece, t3, t1, t2); +- tcg_gen_add_vec(vece, t, t, t3); +-} +- +-static void gen_vmaddwod_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +-{ +- TCGv_i32 t1; +- +- t1 = tcg_temp_new_i32(); +- gen_vmulwod_w_hu_h(t1, a, b); +- tcg_gen_add_i32(t, t, t1); +-} +- +-static void gen_vmaddwod_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +-{ +- TCGv_i64 t1; +- +- t1 = tcg_temp_new_i64(); +- gen_vmulwod_d_wu_w(t1, a, b); +- tcg_gen_add_i64(t, t, t1); +-} +- +-static void do_vmaddwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shri_vec, INDEX_op_sari_vec, +- INDEX_op_mul_vec, INDEX_op_add_vec, 0 +- }; +- static const GVecGen3 op[3] = { +- { +- .fniv = gen_vmaddwod_u_s, +- .fno = gen_helper_vmaddwod_h_bu_b, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fni4 = gen_vmaddwod_w_hu_h, +- .fniv = gen_vmaddwod_u_s, +- .fno = gen_helper_vmaddwod_w_hu_h, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fni8 = gen_vmaddwod_d_wu_w, +- .fniv = gen_vmaddwod_u_s, +- .fno = gen_helper_vmaddwod_d_wu_w, +- .load_dest = true, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vmaddwod_h_bu_b, LSX, gvec_vvv, MO_8, do_vmaddwod_u_s) +-TRANS(vmaddwod_w_hu_h, LSX, gvec_vvv, MO_16, do_vmaddwod_u_s) +-TRANS(vmaddwod_d_wu_w, LSX, gvec_vvv, MO_32, do_vmaddwod_u_s) +-TRANS(xvmaddwod_h_bu_b, LASX, gvec_xxx, MO_8, do_vmaddwod_u_s) +-TRANS(xvmaddwod_w_hu_h, LASX, gvec_xxx, MO_16, do_vmaddwod_u_s) +-TRANS(xvmaddwod_d_wu_w, LASX, gvec_xxx, MO_32, do_vmaddwod_u_s) +- +-TRANS(vdiv_b, LSX, gen_vvv, gen_helper_vdiv_b) +-TRANS(vdiv_h, LSX, gen_vvv, gen_helper_vdiv_h) +-TRANS(vdiv_w, LSX, gen_vvv, gen_helper_vdiv_w) +-TRANS(vdiv_d, LSX, gen_vvv, gen_helper_vdiv_d) +-TRANS(vdiv_bu, LSX, gen_vvv, gen_helper_vdiv_bu) +-TRANS(vdiv_hu, LSX, gen_vvv, gen_helper_vdiv_hu) +-TRANS(vdiv_wu, LSX, gen_vvv, gen_helper_vdiv_wu) +-TRANS(vdiv_du, LSX, gen_vvv, gen_helper_vdiv_du) +-TRANS(vmod_b, LSX, gen_vvv, gen_helper_vmod_b) +-TRANS(vmod_h, LSX, gen_vvv, gen_helper_vmod_h) +-TRANS(vmod_w, LSX, gen_vvv, gen_helper_vmod_w) +-TRANS(vmod_d, LSX, gen_vvv, gen_helper_vmod_d) +-TRANS(vmod_bu, LSX, gen_vvv, gen_helper_vmod_bu) +-TRANS(vmod_hu, LSX, gen_vvv, gen_helper_vmod_hu) +-TRANS(vmod_wu, LSX, gen_vvv, gen_helper_vmod_wu) +-TRANS(vmod_du, LSX, gen_vvv, gen_helper_vmod_du) +-TRANS(xvdiv_b, LASX, gen_xxx, gen_helper_vdiv_b) +-TRANS(xvdiv_h, LASX, gen_xxx, gen_helper_vdiv_h) +-TRANS(xvdiv_w, LASX, gen_xxx, gen_helper_vdiv_w) +-TRANS(xvdiv_d, LASX, gen_xxx, gen_helper_vdiv_d) +-TRANS(xvdiv_bu, LASX, gen_xxx, gen_helper_vdiv_bu) +-TRANS(xvdiv_hu, LASX, gen_xxx, gen_helper_vdiv_hu) +-TRANS(xvdiv_wu, LASX, gen_xxx, gen_helper_vdiv_wu) +-TRANS(xvdiv_du, LASX, gen_xxx, gen_helper_vdiv_du) +-TRANS(xvmod_b, LASX, gen_xxx, gen_helper_vmod_b) +-TRANS(xvmod_h, LASX, gen_xxx, gen_helper_vmod_h) +-TRANS(xvmod_w, LASX, gen_xxx, gen_helper_vmod_w) +-TRANS(xvmod_d, LASX, gen_xxx, gen_helper_vmod_d) +-TRANS(xvmod_bu, LASX, gen_xxx, gen_helper_vmod_bu) +-TRANS(xvmod_hu, LASX, gen_xxx, gen_helper_vmod_hu) +-TRANS(xvmod_wu, LASX, gen_xxx, gen_helper_vmod_wu) +-TRANS(xvmod_du, LASX, gen_xxx, gen_helper_vmod_du) +- +-static void gen_vsat_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec max) +-{ +- TCGv_vec min; +- +- min = tcg_temp_new_vec_matching(t); +- tcg_gen_not_vec(vece, min, max); +- tcg_gen_smax_vec(vece, t, a, min); +- tcg_gen_smin_vec(vece, t, t, max); +-} +- +-static void do_vsat_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- int64_t imm, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_smax_vec, INDEX_op_smin_vec, 0 +- }; +- static const GVecGen2s op[4] = { +- { +- .fniv = gen_vsat_s, +- .fno = gen_helper_vsat_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vsat_s, +- .fno = gen_helper_vsat_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vsat_s, +- .fno = gen_helper_vsat_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vsat_s, +- .fno = gen_helper_vsat_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_2s(vd_ofs, vj_ofs, oprsz, maxsz, +- tcg_constant_i64((1ll<< imm) -1), &op[vece]); +-} +- +-TRANS(vsat_b, LSX, gvec_vv_i, MO_8, do_vsat_s) +-TRANS(vsat_h, LSX, gvec_vv_i, MO_16, do_vsat_s) +-TRANS(vsat_w, LSX, gvec_vv_i, MO_32, do_vsat_s) +-TRANS(vsat_d, LSX, gvec_vv_i, MO_64, do_vsat_s) +-TRANS(xvsat_b, LASX, gvec_xx_i, MO_8, do_vsat_s) +-TRANS(xvsat_h, LASX, gvec_xx_i, MO_16, do_vsat_s) +-TRANS(xvsat_w, LASX, gvec_xx_i, MO_32, do_vsat_s) +-TRANS(xvsat_d, LASX, gvec_xx_i, MO_64, do_vsat_s) +- +-static void gen_vsat_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec max) +-{ +- tcg_gen_umin_vec(vece, t, a, max); +-} +- +-static void do_vsat_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- int64_t imm, uint32_t oprsz, uint32_t maxsz) +-{ +- uint64_t max; +- static const TCGOpcode vecop_list[] = { +- INDEX_op_umin_vec, 0 +- }; +- static const GVecGen2s op[4] = { +- { +- .fniv = gen_vsat_u, +- .fno = gen_helper_vsat_bu, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vsat_u, +- .fno = gen_helper_vsat_hu, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vsat_u, +- .fno = gen_helper_vsat_wu, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vsat_u, +- .fno = gen_helper_vsat_du, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- max = (imm == 0x3f) ? UINT64_MAX : (1ull << (imm + 1)) - 1; +- tcg_gen_gvec_2s(vd_ofs, vj_ofs, oprsz, maxsz, +- tcg_constant_i64(max), &op[vece]); +-} +- +-TRANS(vsat_bu, LSX, gvec_vv_i, MO_8, do_vsat_u) +-TRANS(vsat_hu, LSX, gvec_vv_i, MO_16, do_vsat_u) +-TRANS(vsat_wu, LSX, gvec_vv_i, MO_32, do_vsat_u) +-TRANS(vsat_du, LSX, gvec_vv_i, MO_64, do_vsat_u) +-TRANS(xvsat_bu, LASX, gvec_xx_i, MO_8, do_vsat_u) +-TRANS(xvsat_hu, LASX, gvec_xx_i, MO_16, do_vsat_u) +-TRANS(xvsat_wu, LASX, gvec_xx_i, MO_32, do_vsat_u) +-TRANS(xvsat_du, LASX, gvec_xx_i, MO_64, do_vsat_u) +- +-TRANS(vexth_h_b, LSX, gen_vv, gen_helper_vexth_h_b) +-TRANS(vexth_w_h, LSX, gen_vv, gen_helper_vexth_w_h) +-TRANS(vexth_d_w, LSX, gen_vv, gen_helper_vexth_d_w) +-TRANS(vexth_q_d, LSX, gen_vv, gen_helper_vexth_q_d) +-TRANS(vexth_hu_bu, LSX, gen_vv, gen_helper_vexth_hu_bu) +-TRANS(vexth_wu_hu, LSX, gen_vv, gen_helper_vexth_wu_hu) +-TRANS(vexth_du_wu, LSX, gen_vv, gen_helper_vexth_du_wu) +-TRANS(vexth_qu_du, LSX, gen_vv, gen_helper_vexth_qu_du) +-TRANS(xvexth_h_b, LASX, gen_xx, gen_helper_vexth_h_b) +-TRANS(xvexth_w_h, LASX, gen_xx, gen_helper_vexth_w_h) +-TRANS(xvexth_d_w, LASX, gen_xx, gen_helper_vexth_d_w) +-TRANS(xvexth_q_d, LASX, gen_xx, gen_helper_vexth_q_d) +-TRANS(xvexth_hu_bu, LASX, gen_xx, gen_helper_vexth_hu_bu) +-TRANS(xvexth_wu_hu, LASX, gen_xx, gen_helper_vexth_wu_hu) +-TRANS(xvexth_du_wu, LASX, gen_xx, gen_helper_vexth_du_wu) +-TRANS(xvexth_qu_du, LASX, gen_xx, gen_helper_vexth_qu_du) +- +-TRANS(vext2xv_h_b, LASX, gen_xx, gen_helper_vext2xv_h_b) +-TRANS(vext2xv_w_b, LASX, gen_xx, gen_helper_vext2xv_w_b) +-TRANS(vext2xv_d_b, LASX, gen_xx, gen_helper_vext2xv_d_b) +-TRANS(vext2xv_w_h, LASX, gen_xx, gen_helper_vext2xv_w_h) +-TRANS(vext2xv_d_h, LASX, gen_xx, gen_helper_vext2xv_d_h) +-TRANS(vext2xv_d_w, LASX, gen_xx, gen_helper_vext2xv_d_w) +-TRANS(vext2xv_hu_bu, LASX, gen_xx, gen_helper_vext2xv_hu_bu) +-TRANS(vext2xv_wu_bu, LASX, gen_xx, gen_helper_vext2xv_wu_bu) +-TRANS(vext2xv_du_bu, LASX, gen_xx, gen_helper_vext2xv_du_bu) +-TRANS(vext2xv_wu_hu, LASX, gen_xx, gen_helper_vext2xv_wu_hu) +-TRANS(vext2xv_du_hu, LASX, gen_xx, gen_helper_vext2xv_du_hu) +-TRANS(vext2xv_du_wu, LASX, gen_xx, gen_helper_vext2xv_du_wu) +- +-static void gen_vsigncov(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- TCGv_vec t1, zero; +- +- t1 = tcg_temp_new_vec_matching(t); +- zero = tcg_constant_vec_matching(t, vece, 0); +- +- tcg_gen_neg_vec(vece, t1, b); +- tcg_gen_cmpsel_vec(TCG_COND_LT, vece, t, a, zero, t1, b); +- tcg_gen_cmpsel_vec(TCG_COND_EQ, vece, t, a, zero, zero, t); +-} +- +-static void do_vsigncov(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_neg_vec, INDEX_op_cmpsel_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vsigncov, +- .fno = gen_helper_vsigncov_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vsigncov, +- .fno = gen_helper_vsigncov_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vsigncov, +- .fno = gen_helper_vsigncov_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vsigncov, +- .fno = gen_helper_vsigncov_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vsigncov_b, LSX, gvec_vvv, MO_8, do_vsigncov) +-TRANS(vsigncov_h, LSX, gvec_vvv, MO_16, do_vsigncov) +-TRANS(vsigncov_w, LSX, gvec_vvv, MO_32, do_vsigncov) +-TRANS(vsigncov_d, LSX, gvec_vvv, MO_64, do_vsigncov) +-TRANS(xvsigncov_b, LASX, gvec_xxx, MO_8, do_vsigncov) +-TRANS(xvsigncov_h, LASX, gvec_xxx, MO_16, do_vsigncov) +-TRANS(xvsigncov_w, LASX, gvec_xxx, MO_32, do_vsigncov) +-TRANS(xvsigncov_d, LASX, gvec_xxx, MO_64, do_vsigncov) +- +-TRANS(vmskltz_b, LSX, gen_vv, gen_helper_vmskltz_b) +-TRANS(vmskltz_h, LSX, gen_vv, gen_helper_vmskltz_h) +-TRANS(vmskltz_w, LSX, gen_vv, gen_helper_vmskltz_w) +-TRANS(vmskltz_d, LSX, gen_vv, gen_helper_vmskltz_d) +-TRANS(vmskgez_b, LSX, gen_vv, gen_helper_vmskgez_b) +-TRANS(vmsknz_b, LSX, gen_vv, gen_helper_vmsknz_b) +-TRANS(xvmskltz_b, LASX, gen_xx, gen_helper_vmskltz_b) +-TRANS(xvmskltz_h, LASX, gen_xx, gen_helper_vmskltz_h) +-TRANS(xvmskltz_w, LASX, gen_xx, gen_helper_vmskltz_w) +-TRANS(xvmskltz_d, LASX, gen_xx, gen_helper_vmskltz_d) +-TRANS(xvmskgez_b, LASX, gen_xx, gen_helper_vmskgez_b) +-TRANS(xvmsknz_b, LASX, gen_xx, gen_helper_vmsknz_b) +- +-#define EXPAND_BYTE(bit) ((uint64_t)(bit ? 0xff : 0)) +- +-static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm) +-{ +- int mode; +- uint64_t data, t; +- +- /* +- * imm bit [11:8] is mode, mode value is 0-12. +- * other values are invalid. +- */ +- mode = (imm >> 8) & 0xf; +- t = imm & 0xff; +- switch (mode) { +- case 0: +- /* data: {2{24'0, imm[7:0]}} */ +- data = (t << 32) | t ; +- break; +- case 1: +- /* data: {2{16'0, imm[7:0], 8'0}} */ +- data = (t << 24) | (t << 8); +- break; +- case 2: +- /* data: {2{8'0, imm[7:0], 16'0}} */ +- data = (t << 48) | (t << 16); +- break; +- case 3: +- /* data: {2{imm[7:0], 24'0}} */ +- data = (t << 56) | (t << 24); +- break; +- case 4: +- /* data: {4{8'0, imm[7:0]}} */ +- data = (t << 48) | (t << 32) | (t << 16) | t; +- break; +- case 5: +- /* data: {4{imm[7:0], 8'0}} */ +- data = (t << 56) |(t << 40) | (t << 24) | (t << 8); +- break; +- case 6: +- /* data: {2{16'0, imm[7:0], 8'1}} */ +- data = (t << 40) | ((uint64_t)0xff << 32) | (t << 8) | 0xff; +- break; +- case 7: +- /* data: {2{8'0, imm[7:0], 16'1}} */ +- data = (t << 48) | ((uint64_t)0xffff << 32) | (t << 16) | 0xffff; +- break; +- case 8: +- /* data: {8{imm[7:0]}} */ +- data =(t << 56) | (t << 48) | (t << 40) | (t << 32) | +- (t << 24) | (t << 16) | (t << 8) | t; +- break; +- case 9: +- /* data: {{8{imm[7]}, ..., 8{imm[0]}}} */ +- { +- uint64_t b0,b1,b2,b3,b4,b5,b6,b7; +- b0 = t& 0x1; +- b1 = (t & 0x2) >> 1; +- b2 = (t & 0x4) >> 2; +- b3 = (t & 0x8) >> 3; +- b4 = (t & 0x10) >> 4; +- b5 = (t & 0x20) >> 5; +- b6 = (t & 0x40) >> 6; +- b7 = (t & 0x80) >> 7; +- data = (EXPAND_BYTE(b7) << 56) | +- (EXPAND_BYTE(b6) << 48) | +- (EXPAND_BYTE(b5) << 40) | +- (EXPAND_BYTE(b4) << 32) | +- (EXPAND_BYTE(b3) << 24) | +- (EXPAND_BYTE(b2) << 16) | +- (EXPAND_BYTE(b1) << 8) | +- EXPAND_BYTE(b0); +- } +- break; +- case 10: +- /* data: {2{imm[7], ~imm[6], {5{imm[6]}}, imm[5:0], 19'0}} */ +- { +- uint64_t b6, b7; +- uint64_t t0, t1; +- b6 = (imm & 0x40) >> 6; +- b7 = (imm & 0x80) >> 7; +- t0 = (imm & 0x3f); +- t1 = (b7 << 6) | ((1-b6) << 5) | (uint64_t)(b6 ? 0x1f : 0); +- data = (t1 << 57) | (t0 << 51) | (t1 << 25) | (t0 << 19); +- } +- break; +- case 11: +- /* data: {32'0, imm[7], ~{imm[6]}, 5{imm[6]}, imm[5:0], 19'0} */ +- { +- uint64_t b6,b7; +- uint64_t t0, t1; +- b6 = (imm & 0x40) >> 6; +- b7 = (imm & 0x80) >> 7; +- t0 = (imm & 0x3f); +- t1 = (b7 << 6) | ((1-b6) << 5) | (b6 ? 0x1f : 0); +- data = (t1 << 25) | (t0 << 19); +- } +- break; +- case 12: +- /* data: {imm[7], ~imm[6], 8{imm[6]}, imm[5:0], 48'0} */ +- { +- uint64_t b6,b7; +- uint64_t t0, t1; +- b6 = (imm & 0x40) >> 6; +- b7 = (imm & 0x80) >> 7; +- t0 = (imm & 0x3f); +- t1 = (b7 << 9) | ((1-b6) << 8) | (b6 ? 0xff : 0); +- data = (t1 << 54) | (t0 << 48); +- } +- break; +- default: +- generate_exception(ctx, EXCCODE_INE); +- g_assert_not_reached(); +- } +- return data; +-} +- +-static bool gen_vldi(DisasContext *ctx, arg_vldi *a, uint32_t oprsz) +-{ +- int sel, vece; +- uint64_t value; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- sel = (a->imm >> 12) & 0x1; +- +- if (sel) { +- value = vldi_get_value(ctx, a->imm); +- vece = MO_64; +- } else { +- value = ((int32_t)(a->imm << 22)) >> 22; +- vece = (a->imm >> 10) & 0x3; +- } +- +- tcg_gen_gvec_dup_i64(vece, vec_full_offset(a->vd), oprsz, ctx->vl/8, +- tcg_constant_i64(value)); +- return true; +-} +- +-TRANS(vldi, LSX, gen_vldi, 16) +-TRANS(xvldi, LASX, gen_vldi, 32) +- +-static bool gen_vandn_v(DisasContext *ctx, arg_vvv *a, uint32_t oprsz) +-{ +- uint32_t vd_ofs, vj_ofs, vk_ofs; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- vd_ofs = vec_full_offset(a->vd); +- vj_ofs = vec_full_offset(a->vj); +- vk_ofs = vec_full_offset(a->vk); +- +- tcg_gen_gvec_andc(MO_64, vd_ofs, vk_ofs, vj_ofs, oprsz, ctx->vl / 8); +- return true; +-} +- +-static void gen_vnori(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) +-{ +- TCGv_vec t1; +- +- t1 = tcg_constant_vec_matching(t, vece, imm); +- tcg_gen_nor_vec(vece, t, a, t1); +-} +- +-static void gen_vnori_b(TCGv_i64 t, TCGv_i64 a, int64_t imm) +-{ +- tcg_gen_movi_i64(t, dup_const(MO_8, imm)); +- tcg_gen_nor_i64(t, a, t); +-} +- +-static void do_vnori_b(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- int64_t imm, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_nor_vec, 0 +- }; +- static const GVecGen2i op = { +- .fni8 = gen_vnori_b, +- .fniv = gen_vnori, +- .fnoi = gen_helper_vnori_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }; +- +- tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op); +-} +- +-TRANS(vand_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_and) +-TRANS(vor_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_or) +-TRANS(vxor_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_xor) +-TRANS(vnor_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_nor) +-TRANS(vandn_v, LSX, gen_vandn_v, 16) +-TRANS(vorn_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_orc) +-TRANS(vandi_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_andi) +-TRANS(vori_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_ori) +-TRANS(vxori_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_xori) +-TRANS(vnori_b, LSX, gvec_vv_i, MO_8, do_vnori_b) +-TRANS(xvand_v, LASX, gvec_xxx, MO_64, tcg_gen_gvec_and) +-TRANS(xvor_v, LASX, gvec_xxx, MO_64, tcg_gen_gvec_or) +-TRANS(xvxor_v, LASX, gvec_xxx, MO_64, tcg_gen_gvec_xor) +-TRANS(xvnor_v, LASX, gvec_xxx, MO_64, tcg_gen_gvec_nor) +-TRANS(xvandn_v, LASX, gen_vandn_v, 32) +-TRANS(xvorn_v, LASX, gvec_xxx, MO_64, tcg_gen_gvec_orc) +-TRANS(xvandi_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_andi) +-TRANS(xvori_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_ori) +-TRANS(xvxori_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_xori) +-TRANS(xvnori_b, LASX, gvec_xx_i, MO_8, do_vnori_b) +- +-TRANS(vsll_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_shlv) +-TRANS(vsll_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_shlv) +-TRANS(vsll_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_shlv) +-TRANS(vsll_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_shlv) +-TRANS(vslli_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_shli) +-TRANS(vslli_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_shli) +-TRANS(vslli_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_shli) +-TRANS(vslli_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_shli) +-TRANS(xvsll_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_shlv) +-TRANS(xvsll_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_shlv) +-TRANS(xvsll_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_shlv) +-TRANS(xvsll_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_shlv) +-TRANS(xvslli_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_shli) +-TRANS(xvslli_h, LASX, gvec_xx_i, MO_16, tcg_gen_gvec_shli) +-TRANS(xvslli_w, LASX, gvec_xx_i, MO_32, tcg_gen_gvec_shli) +-TRANS(xvslli_d, LASX, gvec_xx_i, MO_64, tcg_gen_gvec_shli) +- +-TRANS(vsrl_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_shrv) +-TRANS(vsrl_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_shrv) +-TRANS(vsrl_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_shrv) +-TRANS(vsrl_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_shrv) +-TRANS(vsrli_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_shri) +-TRANS(vsrli_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_shri) +-TRANS(vsrli_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_shri) +-TRANS(vsrli_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_shri) +-TRANS(xvsrl_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_shrv) +-TRANS(xvsrl_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_shrv) +-TRANS(xvsrl_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_shrv) +-TRANS(xvsrl_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_shrv) +-TRANS(xvsrli_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_shri) +-TRANS(xvsrli_h, LASX, gvec_xx_i, MO_16, tcg_gen_gvec_shri) +-TRANS(xvsrli_w, LASX, gvec_xx_i, MO_32, tcg_gen_gvec_shri) +-TRANS(xvsrli_d, LASX, gvec_xx_i, MO_64, tcg_gen_gvec_shri) +- +-TRANS(vsra_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_sarv) +-TRANS(vsra_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_sarv) +-TRANS(vsra_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_sarv) +-TRANS(vsra_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_sarv) +-TRANS(vsrai_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_sari) +-TRANS(vsrai_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_sari) +-TRANS(vsrai_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_sari) +-TRANS(vsrai_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_sari) +-TRANS(xvsra_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_sarv) +-TRANS(xvsra_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_sarv) +-TRANS(xvsra_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_sarv) +-TRANS(xvsra_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_sarv) +-TRANS(xvsrai_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_sari) +-TRANS(xvsrai_h, LASX, gvec_xx_i, MO_16, tcg_gen_gvec_sari) +-TRANS(xvsrai_w, LASX, gvec_xx_i, MO_32, tcg_gen_gvec_sari) +-TRANS(xvsrai_d, LASX, gvec_xx_i, MO_64, tcg_gen_gvec_sari) +- +-TRANS(vrotr_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_rotrv) +-TRANS(vrotr_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_rotrv) +-TRANS(vrotr_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_rotrv) +-TRANS(vrotr_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_rotrv) +-TRANS(vrotri_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_rotri) +-TRANS(vrotri_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_rotri) +-TRANS(vrotri_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_rotri) +-TRANS(vrotri_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_rotri) +-TRANS(xvrotr_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_rotrv) +-TRANS(xvrotr_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_rotrv) +-TRANS(xvrotr_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_rotrv) +-TRANS(xvrotr_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_rotrv) +-TRANS(xvrotri_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_rotri) +-TRANS(xvrotri_h, LASX, gvec_xx_i, MO_16, tcg_gen_gvec_rotri) +-TRANS(xvrotri_w, LASX, gvec_xx_i, MO_32, tcg_gen_gvec_rotri) +-TRANS(xvrotri_d, LASX, gvec_xx_i, MO_64, tcg_gen_gvec_rotri) +- +-TRANS(vsllwil_h_b, LSX, gen_vv_i, gen_helper_vsllwil_h_b) +-TRANS(vsllwil_w_h, LSX, gen_vv_i, gen_helper_vsllwil_w_h) +-TRANS(vsllwil_d_w, LSX, gen_vv_i, gen_helper_vsllwil_d_w) +-TRANS(vextl_q_d, LSX, gen_vv, gen_helper_vextl_q_d) +-TRANS(vsllwil_hu_bu, LSX, gen_vv_i, gen_helper_vsllwil_hu_bu) +-TRANS(vsllwil_wu_hu, LSX, gen_vv_i, gen_helper_vsllwil_wu_hu) +-TRANS(vsllwil_du_wu, LSX, gen_vv_i, gen_helper_vsllwil_du_wu) +-TRANS(vextl_qu_du, LSX, gen_vv, gen_helper_vextl_qu_du) +-TRANS(xvsllwil_h_b, LASX, gen_xx_i, gen_helper_vsllwil_h_b) +-TRANS(xvsllwil_w_h, LASX, gen_xx_i, gen_helper_vsllwil_w_h) +-TRANS(xvsllwil_d_w, LASX, gen_xx_i, gen_helper_vsllwil_d_w) +-TRANS(xvextl_q_d, LASX, gen_xx, gen_helper_vextl_q_d) +-TRANS(xvsllwil_hu_bu, LASX, gen_xx_i, gen_helper_vsllwil_hu_bu) +-TRANS(xvsllwil_wu_hu, LASX, gen_xx_i, gen_helper_vsllwil_wu_hu) +-TRANS(xvsllwil_du_wu, LASX, gen_xx_i, gen_helper_vsllwil_du_wu) +-TRANS(xvextl_qu_du, LASX, gen_xx, gen_helper_vextl_qu_du) +- +-TRANS(vsrlr_b, LSX, gen_vvv, gen_helper_vsrlr_b) +-TRANS(vsrlr_h, LSX, gen_vvv, gen_helper_vsrlr_h) +-TRANS(vsrlr_w, LSX, gen_vvv, gen_helper_vsrlr_w) +-TRANS(vsrlr_d, LSX, gen_vvv, gen_helper_vsrlr_d) +-TRANS(vsrlri_b, LSX, gen_vv_i, gen_helper_vsrlri_b) +-TRANS(vsrlri_h, LSX, gen_vv_i, gen_helper_vsrlri_h) +-TRANS(vsrlri_w, LSX, gen_vv_i, gen_helper_vsrlri_w) +-TRANS(vsrlri_d, LSX, gen_vv_i, gen_helper_vsrlri_d) +-TRANS(xvsrlr_b, LASX, gen_xxx, gen_helper_vsrlr_b) +-TRANS(xvsrlr_h, LASX, gen_xxx, gen_helper_vsrlr_h) +-TRANS(xvsrlr_w, LASX, gen_xxx, gen_helper_vsrlr_w) +-TRANS(xvsrlr_d, LASX, gen_xxx, gen_helper_vsrlr_d) +-TRANS(xvsrlri_b, LASX, gen_xx_i, gen_helper_vsrlri_b) +-TRANS(xvsrlri_h, LASX, gen_xx_i, gen_helper_vsrlri_h) +-TRANS(xvsrlri_w, LASX, gen_xx_i, gen_helper_vsrlri_w) +-TRANS(xvsrlri_d, LASX, gen_xx_i, gen_helper_vsrlri_d) +- +-TRANS(vsrar_b, LSX, gen_vvv, gen_helper_vsrar_b) +-TRANS(vsrar_h, LSX, gen_vvv, gen_helper_vsrar_h) +-TRANS(vsrar_w, LSX, gen_vvv, gen_helper_vsrar_w) +-TRANS(vsrar_d, LSX, gen_vvv, gen_helper_vsrar_d) +-TRANS(vsrari_b, LSX, gen_vv_i, gen_helper_vsrari_b) +-TRANS(vsrari_h, LSX, gen_vv_i, gen_helper_vsrari_h) +-TRANS(vsrari_w, LSX, gen_vv_i, gen_helper_vsrari_w) +-TRANS(vsrari_d, LSX, gen_vv_i, gen_helper_vsrari_d) +-TRANS(xvsrar_b, LASX, gen_xxx, gen_helper_vsrar_b) +-TRANS(xvsrar_h, LASX, gen_xxx, gen_helper_vsrar_h) +-TRANS(xvsrar_w, LASX, gen_xxx, gen_helper_vsrar_w) +-TRANS(xvsrar_d, LASX, gen_xxx, gen_helper_vsrar_d) +-TRANS(xvsrari_b, LASX, gen_xx_i, gen_helper_vsrari_b) +-TRANS(xvsrari_h, LASX, gen_xx_i, gen_helper_vsrari_h) +-TRANS(xvsrari_w, LASX, gen_xx_i, gen_helper_vsrari_w) +-TRANS(xvsrari_d, LASX, gen_xx_i, gen_helper_vsrari_d) +- +-TRANS(vsrln_b_h, LSX, gen_vvv, gen_helper_vsrln_b_h) +-TRANS(vsrln_h_w, LSX, gen_vvv, gen_helper_vsrln_h_w) +-TRANS(vsrln_w_d, LSX, gen_vvv, gen_helper_vsrln_w_d) +-TRANS(vsran_b_h, LSX, gen_vvv, gen_helper_vsran_b_h) +-TRANS(vsran_h_w, LSX, gen_vvv, gen_helper_vsran_h_w) +-TRANS(vsran_w_d, LSX, gen_vvv, gen_helper_vsran_w_d) +-TRANS(xvsrln_b_h, LASX, gen_xxx, gen_helper_vsrln_b_h) +-TRANS(xvsrln_h_w, LASX, gen_xxx, gen_helper_vsrln_h_w) +-TRANS(xvsrln_w_d, LASX, gen_xxx, gen_helper_vsrln_w_d) +-TRANS(xvsran_b_h, LASX, gen_xxx, gen_helper_vsran_b_h) +-TRANS(xvsran_h_w, LASX, gen_xxx, gen_helper_vsran_h_w) +-TRANS(xvsran_w_d, LASX, gen_xxx, gen_helper_vsran_w_d) +- +-TRANS(vsrlni_b_h, LSX, gen_vv_i, gen_helper_vsrlni_b_h) +-TRANS(vsrlni_h_w, LSX, gen_vv_i, gen_helper_vsrlni_h_w) +-TRANS(vsrlni_w_d, LSX, gen_vv_i, gen_helper_vsrlni_w_d) +-TRANS(vsrlni_d_q, LSX, gen_vv_i, gen_helper_vsrlni_d_q) +-TRANS(vsrani_b_h, LSX, gen_vv_i, gen_helper_vsrani_b_h) +-TRANS(vsrani_h_w, LSX, gen_vv_i, gen_helper_vsrani_h_w) +-TRANS(vsrani_w_d, LSX, gen_vv_i, gen_helper_vsrani_w_d) +-TRANS(vsrani_d_q, LSX, gen_vv_i, gen_helper_vsrani_d_q) +-TRANS(xvsrlni_b_h, LASX, gen_xx_i, gen_helper_vsrlni_b_h) +-TRANS(xvsrlni_h_w, LASX, gen_xx_i, gen_helper_vsrlni_h_w) +-TRANS(xvsrlni_w_d, LASX, gen_xx_i, gen_helper_vsrlni_w_d) +-TRANS(xvsrlni_d_q, LASX, gen_xx_i, gen_helper_vsrlni_d_q) +-TRANS(xvsrani_b_h, LASX, gen_xx_i, gen_helper_vsrani_b_h) +-TRANS(xvsrani_h_w, LASX, gen_xx_i, gen_helper_vsrani_h_w) +-TRANS(xvsrani_w_d, LASX, gen_xx_i, gen_helper_vsrani_w_d) +-TRANS(xvsrani_d_q, LASX, gen_xx_i, gen_helper_vsrani_d_q) +- +-TRANS(vsrlrn_b_h, LSX, gen_vvv, gen_helper_vsrlrn_b_h) +-TRANS(vsrlrn_h_w, LSX, gen_vvv, gen_helper_vsrlrn_h_w) +-TRANS(vsrlrn_w_d, LSX, gen_vvv, gen_helper_vsrlrn_w_d) +-TRANS(vsrarn_b_h, LSX, gen_vvv, gen_helper_vsrarn_b_h) +-TRANS(vsrarn_h_w, LSX, gen_vvv, gen_helper_vsrarn_h_w) +-TRANS(vsrarn_w_d, LSX, gen_vvv, gen_helper_vsrarn_w_d) +-TRANS(xvsrlrn_b_h, LASX, gen_xxx, gen_helper_vsrlrn_b_h) +-TRANS(xvsrlrn_h_w, LASX, gen_xxx, gen_helper_vsrlrn_h_w) +-TRANS(xvsrlrn_w_d, LASX, gen_xxx, gen_helper_vsrlrn_w_d) +-TRANS(xvsrarn_b_h, LASX, gen_xxx, gen_helper_vsrarn_b_h) +-TRANS(xvsrarn_h_w, LASX, gen_xxx, gen_helper_vsrarn_h_w) +-TRANS(xvsrarn_w_d, LASX, gen_xxx, gen_helper_vsrarn_w_d) +- +-TRANS(vsrlrni_b_h, LSX, gen_vv_i, gen_helper_vsrlrni_b_h) +-TRANS(vsrlrni_h_w, LSX, gen_vv_i, gen_helper_vsrlrni_h_w) +-TRANS(vsrlrni_w_d, LSX, gen_vv_i, gen_helper_vsrlrni_w_d) +-TRANS(vsrlrni_d_q, LSX, gen_vv_i, gen_helper_vsrlrni_d_q) +-TRANS(vsrarni_b_h, LSX, gen_vv_i, gen_helper_vsrarni_b_h) +-TRANS(vsrarni_h_w, LSX, gen_vv_i, gen_helper_vsrarni_h_w) +-TRANS(vsrarni_w_d, LSX, gen_vv_i, gen_helper_vsrarni_w_d) +-TRANS(vsrarni_d_q, LSX, gen_vv_i, gen_helper_vsrarni_d_q) +-TRANS(xvsrlrni_b_h, LASX, gen_xx_i, gen_helper_vsrlrni_b_h) +-TRANS(xvsrlrni_h_w, LASX, gen_xx_i, gen_helper_vsrlrni_h_w) +-TRANS(xvsrlrni_w_d, LASX, gen_xx_i, gen_helper_vsrlrni_w_d) +-TRANS(xvsrlrni_d_q, LASX, gen_xx_i, gen_helper_vsrlrni_d_q) +-TRANS(xvsrarni_b_h, LASX, gen_xx_i, gen_helper_vsrarni_b_h) +-TRANS(xvsrarni_h_w, LASX, gen_xx_i, gen_helper_vsrarni_h_w) +-TRANS(xvsrarni_w_d, LASX, gen_xx_i, gen_helper_vsrarni_w_d) +-TRANS(xvsrarni_d_q, LASX, gen_xx_i, gen_helper_vsrarni_d_q) +- +-TRANS(vssrln_b_h, LSX, gen_vvv, gen_helper_vssrln_b_h) +-TRANS(vssrln_h_w, LSX, gen_vvv, gen_helper_vssrln_h_w) +-TRANS(vssrln_w_d, LSX, gen_vvv, gen_helper_vssrln_w_d) +-TRANS(vssran_b_h, LSX, gen_vvv, gen_helper_vssran_b_h) +-TRANS(vssran_h_w, LSX, gen_vvv, gen_helper_vssran_h_w) +-TRANS(vssran_w_d, LSX, gen_vvv, gen_helper_vssran_w_d) +-TRANS(vssrln_bu_h, LSX, gen_vvv, gen_helper_vssrln_bu_h) +-TRANS(vssrln_hu_w, LSX, gen_vvv, gen_helper_vssrln_hu_w) +-TRANS(vssrln_wu_d, LSX, gen_vvv, gen_helper_vssrln_wu_d) +-TRANS(vssran_bu_h, LSX, gen_vvv, gen_helper_vssran_bu_h) +-TRANS(vssran_hu_w, LSX, gen_vvv, gen_helper_vssran_hu_w) +-TRANS(vssran_wu_d, LSX, gen_vvv, gen_helper_vssran_wu_d) +-TRANS(xvssrln_b_h, LASX, gen_xxx, gen_helper_vssrln_b_h) +-TRANS(xvssrln_h_w, LASX, gen_xxx, gen_helper_vssrln_h_w) +-TRANS(xvssrln_w_d, LASX, gen_xxx, gen_helper_vssrln_w_d) +-TRANS(xvssran_b_h, LASX, gen_xxx, gen_helper_vssran_b_h) +-TRANS(xvssran_h_w, LASX, gen_xxx, gen_helper_vssran_h_w) +-TRANS(xvssran_w_d, LASX, gen_xxx, gen_helper_vssran_w_d) +-TRANS(xvssrln_bu_h, LASX, gen_xxx, gen_helper_vssrln_bu_h) +-TRANS(xvssrln_hu_w, LASX, gen_xxx, gen_helper_vssrln_hu_w) +-TRANS(xvssrln_wu_d, LASX, gen_xxx, gen_helper_vssrln_wu_d) +-TRANS(xvssran_bu_h, LASX, gen_xxx, gen_helper_vssran_bu_h) +-TRANS(xvssran_hu_w, LASX, gen_xxx, gen_helper_vssran_hu_w) +-TRANS(xvssran_wu_d, LASX, gen_xxx, gen_helper_vssran_wu_d) +- +-TRANS(vssrlni_b_h, LSX, gen_vv_i, gen_helper_vssrlni_b_h) +-TRANS(vssrlni_h_w, LSX, gen_vv_i, gen_helper_vssrlni_h_w) +-TRANS(vssrlni_w_d, LSX, gen_vv_i, gen_helper_vssrlni_w_d) +-TRANS(vssrlni_d_q, LSX, gen_vv_i, gen_helper_vssrlni_d_q) +-TRANS(vssrani_b_h, LSX, gen_vv_i, gen_helper_vssrani_b_h) +-TRANS(vssrani_h_w, LSX, gen_vv_i, gen_helper_vssrani_h_w) +-TRANS(vssrani_w_d, LSX, gen_vv_i, gen_helper_vssrani_w_d) +-TRANS(vssrani_d_q, LSX, gen_vv_i, gen_helper_vssrani_d_q) +-TRANS(vssrlni_bu_h, LSX, gen_vv_i, gen_helper_vssrlni_bu_h) +-TRANS(vssrlni_hu_w, LSX, gen_vv_i, gen_helper_vssrlni_hu_w) +-TRANS(vssrlni_wu_d, LSX, gen_vv_i, gen_helper_vssrlni_wu_d) +-TRANS(vssrlni_du_q, LSX, gen_vv_i, gen_helper_vssrlni_du_q) +-TRANS(vssrani_bu_h, LSX, gen_vv_i, gen_helper_vssrani_bu_h) +-TRANS(vssrani_hu_w, LSX, gen_vv_i, gen_helper_vssrani_hu_w) +-TRANS(vssrani_wu_d, LSX, gen_vv_i, gen_helper_vssrani_wu_d) +-TRANS(vssrani_du_q, LSX, gen_vv_i, gen_helper_vssrani_du_q) +-TRANS(xvssrlni_b_h, LASX, gen_xx_i, gen_helper_vssrlni_b_h) +-TRANS(xvssrlni_h_w, LASX, gen_xx_i, gen_helper_vssrlni_h_w) +-TRANS(xvssrlni_w_d, LASX, gen_xx_i, gen_helper_vssrlni_w_d) +-TRANS(xvssrlni_d_q, LASX, gen_xx_i, gen_helper_vssrlni_d_q) +-TRANS(xvssrani_b_h, LASX, gen_xx_i, gen_helper_vssrani_b_h) +-TRANS(xvssrani_h_w, LASX, gen_xx_i, gen_helper_vssrani_h_w) +-TRANS(xvssrani_w_d, LASX, gen_xx_i, gen_helper_vssrani_w_d) +-TRANS(xvssrani_d_q, LASX, gen_xx_i, gen_helper_vssrani_d_q) +-TRANS(xvssrlni_bu_h, LASX, gen_xx_i, gen_helper_vssrlni_bu_h) +-TRANS(xvssrlni_hu_w, LASX, gen_xx_i, gen_helper_vssrlni_hu_w) +-TRANS(xvssrlni_wu_d, LASX, gen_xx_i, gen_helper_vssrlni_wu_d) +-TRANS(xvssrlni_du_q, LASX, gen_xx_i, gen_helper_vssrlni_du_q) +-TRANS(xvssrani_bu_h, LASX, gen_xx_i, gen_helper_vssrani_bu_h) +-TRANS(xvssrani_hu_w, LASX, gen_xx_i, gen_helper_vssrani_hu_w) +-TRANS(xvssrani_wu_d, LASX, gen_xx_i, gen_helper_vssrani_wu_d) +-TRANS(xvssrani_du_q, LASX, gen_xx_i, gen_helper_vssrani_du_q) +- +-TRANS(vssrlrn_b_h, LSX, gen_vvv, gen_helper_vssrlrn_b_h) +-TRANS(vssrlrn_h_w, LSX, gen_vvv, gen_helper_vssrlrn_h_w) +-TRANS(vssrlrn_w_d, LSX, gen_vvv, gen_helper_vssrlrn_w_d) +-TRANS(vssrarn_b_h, LSX, gen_vvv, gen_helper_vssrarn_b_h) +-TRANS(vssrarn_h_w, LSX, gen_vvv, gen_helper_vssrarn_h_w) +-TRANS(vssrarn_w_d, LSX, gen_vvv, gen_helper_vssrarn_w_d) +-TRANS(vssrlrn_bu_h, LSX, gen_vvv, gen_helper_vssrlrn_bu_h) +-TRANS(vssrlrn_hu_w, LSX, gen_vvv, gen_helper_vssrlrn_hu_w) +-TRANS(vssrlrn_wu_d, LSX, gen_vvv, gen_helper_vssrlrn_wu_d) +-TRANS(vssrarn_bu_h, LSX, gen_vvv, gen_helper_vssrarn_bu_h) +-TRANS(vssrarn_hu_w, LSX, gen_vvv, gen_helper_vssrarn_hu_w) +-TRANS(vssrarn_wu_d, LSX, gen_vvv, gen_helper_vssrarn_wu_d) +-TRANS(xvssrlrn_b_h, LASX, gen_xxx, gen_helper_vssrlrn_b_h) +-TRANS(xvssrlrn_h_w, LASX, gen_xxx, gen_helper_vssrlrn_h_w) +-TRANS(xvssrlrn_w_d, LASX, gen_xxx, gen_helper_vssrlrn_w_d) +-TRANS(xvssrarn_b_h, LASX, gen_xxx, gen_helper_vssrarn_b_h) +-TRANS(xvssrarn_h_w, LASX, gen_xxx, gen_helper_vssrarn_h_w) +-TRANS(xvssrarn_w_d, LASX, gen_xxx, gen_helper_vssrarn_w_d) +-TRANS(xvssrlrn_bu_h, LASX, gen_xxx, gen_helper_vssrlrn_bu_h) +-TRANS(xvssrlrn_hu_w, LASX, gen_xxx, gen_helper_vssrlrn_hu_w) +-TRANS(xvssrlrn_wu_d, LASX, gen_xxx, gen_helper_vssrlrn_wu_d) +-TRANS(xvssrarn_bu_h, LASX, gen_xxx, gen_helper_vssrarn_bu_h) +-TRANS(xvssrarn_hu_w, LASX, gen_xxx, gen_helper_vssrarn_hu_w) +-TRANS(xvssrarn_wu_d, LASX, gen_xxx, gen_helper_vssrarn_wu_d) +- +-TRANS(vssrlrni_b_h, LSX, gen_vv_i, gen_helper_vssrlrni_b_h) +-TRANS(vssrlrni_h_w, LSX, gen_vv_i, gen_helper_vssrlrni_h_w) +-TRANS(vssrlrni_w_d, LSX, gen_vv_i, gen_helper_vssrlrni_w_d) +-TRANS(vssrlrni_d_q, LSX, gen_vv_i, gen_helper_vssrlrni_d_q) +-TRANS(vssrarni_b_h, LSX, gen_vv_i, gen_helper_vssrarni_b_h) +-TRANS(vssrarni_h_w, LSX, gen_vv_i, gen_helper_vssrarni_h_w) +-TRANS(vssrarni_w_d, LSX, gen_vv_i, gen_helper_vssrarni_w_d) +-TRANS(vssrarni_d_q, LSX, gen_vv_i, gen_helper_vssrarni_d_q) +-TRANS(vssrlrni_bu_h, LSX, gen_vv_i, gen_helper_vssrlrni_bu_h) +-TRANS(vssrlrni_hu_w, LSX, gen_vv_i, gen_helper_vssrlrni_hu_w) +-TRANS(vssrlrni_wu_d, LSX, gen_vv_i, gen_helper_vssrlrni_wu_d) +-TRANS(vssrlrni_du_q, LSX, gen_vv_i, gen_helper_vssrlrni_du_q) +-TRANS(vssrarni_bu_h, LSX, gen_vv_i, gen_helper_vssrarni_bu_h) +-TRANS(vssrarni_hu_w, LSX, gen_vv_i, gen_helper_vssrarni_hu_w) +-TRANS(vssrarni_wu_d, LSX, gen_vv_i, gen_helper_vssrarni_wu_d) +-TRANS(vssrarni_du_q, LSX, gen_vv_i, gen_helper_vssrarni_du_q) +-TRANS(xvssrlrni_b_h, LASX, gen_xx_i, gen_helper_vssrlrni_b_h) +-TRANS(xvssrlrni_h_w, LASX, gen_xx_i, gen_helper_vssrlrni_h_w) +-TRANS(xvssrlrni_w_d, LASX, gen_xx_i, gen_helper_vssrlrni_w_d) +-TRANS(xvssrlrni_d_q, LASX, gen_xx_i, gen_helper_vssrlrni_d_q) +-TRANS(xvssrarni_b_h, LASX, gen_xx_i, gen_helper_vssrarni_b_h) +-TRANS(xvssrarni_h_w, LASX, gen_xx_i, gen_helper_vssrarni_h_w) +-TRANS(xvssrarni_w_d, LASX, gen_xx_i, gen_helper_vssrarni_w_d) +-TRANS(xvssrarni_d_q, LASX, gen_xx_i, gen_helper_vssrarni_d_q) +-TRANS(xvssrlrni_bu_h, LASX, gen_xx_i, gen_helper_vssrlrni_bu_h) +-TRANS(xvssrlrni_hu_w, LASX, gen_xx_i, gen_helper_vssrlrni_hu_w) +-TRANS(xvssrlrni_wu_d, LASX, gen_xx_i, gen_helper_vssrlrni_wu_d) +-TRANS(xvssrlrni_du_q, LASX, gen_xx_i, gen_helper_vssrlrni_du_q) +-TRANS(xvssrarni_bu_h, LASX, gen_xx_i, gen_helper_vssrarni_bu_h) +-TRANS(xvssrarni_hu_w, LASX, gen_xx_i, gen_helper_vssrarni_hu_w) +-TRANS(xvssrarni_wu_d, LASX, gen_xx_i, gen_helper_vssrarni_wu_d) +-TRANS(xvssrarni_du_q, LASX, gen_xx_i, gen_helper_vssrarni_du_q) +- +-TRANS(vclo_b, LSX, gen_vv, gen_helper_vclo_b) +-TRANS(vclo_h, LSX, gen_vv, gen_helper_vclo_h) +-TRANS(vclo_w, LSX, gen_vv, gen_helper_vclo_w) +-TRANS(vclo_d, LSX, gen_vv, gen_helper_vclo_d) +-TRANS(vclz_b, LSX, gen_vv, gen_helper_vclz_b) +-TRANS(vclz_h, LSX, gen_vv, gen_helper_vclz_h) +-TRANS(vclz_w, LSX, gen_vv, gen_helper_vclz_w) +-TRANS(vclz_d, LSX, gen_vv, gen_helper_vclz_d) +-TRANS(xvclo_b, LASX, gen_xx, gen_helper_vclo_b) +-TRANS(xvclo_h, LASX, gen_xx, gen_helper_vclo_h) +-TRANS(xvclo_w, LASX, gen_xx, gen_helper_vclo_w) +-TRANS(xvclo_d, LASX, gen_xx, gen_helper_vclo_d) +-TRANS(xvclz_b, LASX, gen_xx, gen_helper_vclz_b) +-TRANS(xvclz_h, LASX, gen_xx, gen_helper_vclz_h) +-TRANS(xvclz_w, LASX, gen_xx, gen_helper_vclz_w) +-TRANS(xvclz_d, LASX, gen_xx, gen_helper_vclz_d) +- +-TRANS(vpcnt_b, LSX, gen_vv, gen_helper_vpcnt_b) +-TRANS(vpcnt_h, LSX, gen_vv, gen_helper_vpcnt_h) +-TRANS(vpcnt_w, LSX, gen_vv, gen_helper_vpcnt_w) +-TRANS(vpcnt_d, LSX, gen_vv, gen_helper_vpcnt_d) +-TRANS(xvpcnt_b, LASX, gen_xx, gen_helper_vpcnt_b) +-TRANS(xvpcnt_h, LASX, gen_xx, gen_helper_vpcnt_h) +-TRANS(xvpcnt_w, LASX, gen_xx, gen_helper_vpcnt_w) +-TRANS(xvpcnt_d, LASX, gen_xx, gen_helper_vpcnt_d) +- +-static void do_vbit(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, +- void (*func)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) +-{ +- TCGv_vec mask, lsh, t1, one; +- +- lsh = tcg_temp_new_vec_matching(t); +- t1 = tcg_temp_new_vec_matching(t); +- mask = tcg_constant_vec_matching(t, vece, (8 << vece) - 1); +- one = tcg_constant_vec_matching(t, vece, 1); +- +- tcg_gen_and_vec(vece, lsh, b, mask); +- tcg_gen_shlv_vec(vece, t1, one, lsh); +- func(vece, t, a, t1); +-} +- +-static void gen_vbitclr(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- do_vbit(vece, t, a, b, tcg_gen_andc_vec); +-} +- +-static void gen_vbitset(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- do_vbit(vece, t, a, b, tcg_gen_or_vec); +-} +- +-static void gen_vbitrev(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +-{ +- do_vbit(vece, t, a, b, tcg_gen_xor_vec); +-} +- +-static void do_vbitclr(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shlv_vec, INDEX_op_andc_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vbitclr, +- .fno = gen_helper_vbitclr_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vbitclr, +- .fno = gen_helper_vbitclr_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vbitclr, +- .fno = gen_helper_vbitclr_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vbitclr, +- .fno = gen_helper_vbitclr_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vbitclr_b, LSX, gvec_vvv, MO_8, do_vbitclr) +-TRANS(vbitclr_h, LSX, gvec_vvv, MO_16, do_vbitclr) +-TRANS(vbitclr_w, LSX, gvec_vvv, MO_32, do_vbitclr) +-TRANS(vbitclr_d, LSX, gvec_vvv, MO_64, do_vbitclr) +-TRANS(xvbitclr_b, LASX, gvec_xxx, MO_8, do_vbitclr) +-TRANS(xvbitclr_h, LASX, gvec_xxx, MO_16, do_vbitclr) +-TRANS(xvbitclr_w, LASX, gvec_xxx, MO_32, do_vbitclr) +-TRANS(xvbitclr_d, LASX, gvec_xxx, MO_64, do_vbitclr) +- +-static void do_vbiti(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm, +- void (*func)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) +-{ +- int lsh; +- TCGv_vec t1, one; +- +- lsh = imm & ((8 << vece) -1); +- t1 = tcg_temp_new_vec_matching(t); +- one = tcg_constant_vec_matching(t, vece, 1); +- +- tcg_gen_shli_vec(vece, t1, one, lsh); +- func(vece, t, a, t1); +-} +- +-static void gen_vbitclri(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) +-{ +- do_vbiti(vece, t, a, imm, tcg_gen_andc_vec); +-} +- +-static void gen_vbitseti(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) +-{ +- do_vbiti(vece, t, a, imm, tcg_gen_or_vec); +-} +- +-static void gen_vbitrevi(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) +-{ +- do_vbiti(vece, t, a, imm, tcg_gen_xor_vec); +-} +- +-static void do_vbitclri(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- int64_t imm, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shli_vec, INDEX_op_andc_vec, 0 +- }; +- static const GVecGen2i op[4] = { +- { +- .fniv = gen_vbitclri, +- .fnoi = gen_helper_vbitclri_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vbitclri, +- .fnoi = gen_helper_vbitclri_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vbitclri, +- .fnoi = gen_helper_vbitclri_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vbitclri, +- .fnoi = gen_helper_vbitclri_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); +-} +- +-TRANS(vbitclri_b, LSX, gvec_vv_i, MO_8, do_vbitclri) +-TRANS(vbitclri_h, LSX, gvec_vv_i, MO_16, do_vbitclri) +-TRANS(vbitclri_w, LSX, gvec_vv_i, MO_32, do_vbitclri) +-TRANS(vbitclri_d, LSX, gvec_vv_i, MO_64, do_vbitclri) +-TRANS(xvbitclri_b, LASX, gvec_xx_i, MO_8, do_vbitclri) +-TRANS(xvbitclri_h, LASX, gvec_xx_i, MO_16, do_vbitclri) +-TRANS(xvbitclri_w, LASX, gvec_xx_i, MO_32, do_vbitclri) +-TRANS(xvbitclri_d, LASX, gvec_xx_i, MO_64, do_vbitclri) +- +-static void do_vbitset(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shlv_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vbitset, +- .fno = gen_helper_vbitset_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vbitset, +- .fno = gen_helper_vbitset_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vbitset, +- .fno = gen_helper_vbitset_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vbitset, +- .fno = gen_helper_vbitset_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vbitset_b, LSX, gvec_vvv, MO_8, do_vbitset) +-TRANS(vbitset_h, LSX, gvec_vvv, MO_16, do_vbitset) +-TRANS(vbitset_w, LSX, gvec_vvv, MO_32, do_vbitset) +-TRANS(vbitset_d, LSX, gvec_vvv, MO_64, do_vbitset) +-TRANS(xvbitset_b, LASX, gvec_xxx, MO_8, do_vbitset) +-TRANS(xvbitset_h, LASX, gvec_xxx, MO_16, do_vbitset) +-TRANS(xvbitset_w, LASX, gvec_xxx, MO_32, do_vbitset) +-TRANS(xvbitset_d, LASX, gvec_xxx, MO_64, do_vbitset) +- +-static void do_vbitseti(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- int64_t imm, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shli_vec, 0 +- }; +- static const GVecGen2i op[4] = { +- { +- .fniv = gen_vbitseti, +- .fnoi = gen_helper_vbitseti_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vbitseti, +- .fnoi = gen_helper_vbitseti_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vbitseti, +- .fnoi = gen_helper_vbitseti_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vbitseti, +- .fnoi = gen_helper_vbitseti_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); +-} +- +-TRANS(vbitseti_b, LSX, gvec_vv_i, MO_8, do_vbitseti) +-TRANS(vbitseti_h, LSX, gvec_vv_i, MO_16, do_vbitseti) +-TRANS(vbitseti_w, LSX, gvec_vv_i, MO_32, do_vbitseti) +-TRANS(vbitseti_d, LSX, gvec_vv_i, MO_64, do_vbitseti) +-TRANS(xvbitseti_b, LASX, gvec_xx_i, MO_8, do_vbitseti) +-TRANS(xvbitseti_h, LASX, gvec_xx_i, MO_16, do_vbitseti) +-TRANS(xvbitseti_w, LASX, gvec_xx_i, MO_32, do_vbitseti) +-TRANS(xvbitseti_d, LASX, gvec_xx_i, MO_64, do_vbitseti) +- +-static void do_vbitrev(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shlv_vec, 0 +- }; +- static const GVecGen3 op[4] = { +- { +- .fniv = gen_vbitrev, +- .fno = gen_helper_vbitrev_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vbitrev, +- .fno = gen_helper_vbitrev_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vbitrev, +- .fno = gen_helper_vbitrev_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vbitrev, +- .fno = gen_helper_vbitrev_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); +-} +- +-TRANS(vbitrev_b, LSX, gvec_vvv, MO_8, do_vbitrev) +-TRANS(vbitrev_h, LSX, gvec_vvv, MO_16, do_vbitrev) +-TRANS(vbitrev_w, LSX, gvec_vvv, MO_32, do_vbitrev) +-TRANS(vbitrev_d, LSX, gvec_vvv, MO_64, do_vbitrev) +-TRANS(xvbitrev_b, LASX, gvec_xxx, MO_8, do_vbitrev) +-TRANS(xvbitrev_h, LASX, gvec_xxx, MO_16, do_vbitrev) +-TRANS(xvbitrev_w, LASX, gvec_xxx, MO_32, do_vbitrev) +-TRANS(xvbitrev_d, LASX, gvec_xxx, MO_64, do_vbitrev) +- +-static void do_vbitrevi(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, +- int64_t imm, uint32_t oprsz, uint32_t maxsz) +-{ +- static const TCGOpcode vecop_list[] = { +- INDEX_op_shli_vec, 0 +- }; +- static const GVecGen2i op[4] = { +- { +- .fniv = gen_vbitrevi, +- .fnoi = gen_helper_vbitrevi_b, +- .opt_opc = vecop_list, +- .vece = MO_8 +- }, +- { +- .fniv = gen_vbitrevi, +- .fnoi = gen_helper_vbitrevi_h, +- .opt_opc = vecop_list, +- .vece = MO_16 +- }, +- { +- .fniv = gen_vbitrevi, +- .fnoi = gen_helper_vbitrevi_w, +- .opt_opc = vecop_list, +- .vece = MO_32 +- }, +- { +- .fniv = gen_vbitrevi, +- .fnoi = gen_helper_vbitrevi_d, +- .opt_opc = vecop_list, +- .vece = MO_64 +- }, +- }; +- +- tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); +-} +- +-TRANS(vbitrevi_b, LSX, gvec_vv_i, MO_8, do_vbitrevi) +-TRANS(vbitrevi_h, LSX, gvec_vv_i, MO_16, do_vbitrevi) +-TRANS(vbitrevi_w, LSX, gvec_vv_i, MO_32, do_vbitrevi) +-TRANS(vbitrevi_d, LSX, gvec_vv_i, MO_64, do_vbitrevi) +-TRANS(xvbitrevi_b, LASX, gvec_xx_i, MO_8, do_vbitrevi) +-TRANS(xvbitrevi_h, LASX, gvec_xx_i, MO_16, do_vbitrevi) +-TRANS(xvbitrevi_w, LASX, gvec_xx_i, MO_32, do_vbitrevi) +-TRANS(xvbitrevi_d, LASX, gvec_xx_i, MO_64, do_vbitrevi) +- +-TRANS(vfrstp_b, LSX, gen_vvv, gen_helper_vfrstp_b) +-TRANS(vfrstp_h, LSX, gen_vvv, gen_helper_vfrstp_h) +-TRANS(vfrstpi_b, LSX, gen_vv_i, gen_helper_vfrstpi_b) +-TRANS(vfrstpi_h, LSX, gen_vv_i, gen_helper_vfrstpi_h) +-TRANS(xvfrstp_b, LASX, gen_xxx, gen_helper_vfrstp_b) +-TRANS(xvfrstp_h, LASX, gen_xxx, gen_helper_vfrstp_h) +-TRANS(xvfrstpi_b, LASX, gen_xx_i, gen_helper_vfrstpi_b) +-TRANS(xvfrstpi_h, LASX, gen_xx_i, gen_helper_vfrstpi_h) +- +-TRANS(vfadd_s, LSX, gen_vvv_ptr, gen_helper_vfadd_s) +-TRANS(vfadd_d, LSX, gen_vvv_ptr, gen_helper_vfadd_d) +-TRANS(vfsub_s, LSX, gen_vvv_ptr, gen_helper_vfsub_s) +-TRANS(vfsub_d, LSX, gen_vvv_ptr, gen_helper_vfsub_d) +-TRANS(vfmul_s, LSX, gen_vvv_ptr, gen_helper_vfmul_s) +-TRANS(vfmul_d, LSX, gen_vvv_ptr, gen_helper_vfmul_d) +-TRANS(vfdiv_s, LSX, gen_vvv_ptr, gen_helper_vfdiv_s) +-TRANS(vfdiv_d, LSX, gen_vvv_ptr, gen_helper_vfdiv_d) +-TRANS(xvfadd_s, LASX, gen_xxx_ptr, gen_helper_vfadd_s) +-TRANS(xvfadd_d, LASX, gen_xxx_ptr, gen_helper_vfadd_d) +-TRANS(xvfsub_s, LASX, gen_xxx_ptr, gen_helper_vfsub_s) +-TRANS(xvfsub_d, LASX, gen_xxx_ptr, gen_helper_vfsub_d) +-TRANS(xvfmul_s, LASX, gen_xxx_ptr, gen_helper_vfmul_s) +-TRANS(xvfmul_d, LASX, gen_xxx_ptr, gen_helper_vfmul_d) +-TRANS(xvfdiv_s, LASX, gen_xxx_ptr, gen_helper_vfdiv_s) +-TRANS(xvfdiv_d, LASX, gen_xxx_ptr, gen_helper_vfdiv_d) +- +-TRANS(vfmadd_s, LSX, gen_vvvv_ptr, gen_helper_vfmadd_s) +-TRANS(vfmadd_d, LSX, gen_vvvv_ptr, gen_helper_vfmadd_d) +-TRANS(vfmsub_s, LSX, gen_vvvv_ptr, gen_helper_vfmsub_s) +-TRANS(vfmsub_d, LSX, gen_vvvv_ptr, gen_helper_vfmsub_d) +-TRANS(vfnmadd_s, LSX, gen_vvvv_ptr, gen_helper_vfnmadd_s) +-TRANS(vfnmadd_d, LSX, gen_vvvv_ptr, gen_helper_vfnmadd_d) +-TRANS(vfnmsub_s, LSX, gen_vvvv_ptr, gen_helper_vfnmsub_s) +-TRANS(vfnmsub_d, LSX, gen_vvvv_ptr, gen_helper_vfnmsub_d) +-TRANS(xvfmadd_s, LASX, gen_xxxx_ptr, gen_helper_vfmadd_s) +-TRANS(xvfmadd_d, LASX, gen_xxxx_ptr, gen_helper_vfmadd_d) +-TRANS(xvfmsub_s, LASX, gen_xxxx_ptr, gen_helper_vfmsub_s) +-TRANS(xvfmsub_d, LASX, gen_xxxx_ptr, gen_helper_vfmsub_d) +-TRANS(xvfnmadd_s, LASX, gen_xxxx_ptr, gen_helper_vfnmadd_s) +-TRANS(xvfnmadd_d, LASX, gen_xxxx_ptr, gen_helper_vfnmadd_d) +-TRANS(xvfnmsub_s, LASX, gen_xxxx_ptr, gen_helper_vfnmsub_s) +-TRANS(xvfnmsub_d, LASX, gen_xxxx_ptr, gen_helper_vfnmsub_d) +- +-TRANS(vfmax_s, LSX, gen_vvv_ptr, gen_helper_vfmax_s) +-TRANS(vfmax_d, LSX, gen_vvv_ptr, gen_helper_vfmax_d) +-TRANS(vfmin_s, LSX, gen_vvv_ptr, gen_helper_vfmin_s) +-TRANS(vfmin_d, LSX, gen_vvv_ptr, gen_helper_vfmin_d) +-TRANS(xvfmax_s, LASX, gen_xxx_ptr, gen_helper_vfmax_s) +-TRANS(xvfmax_d, LASX, gen_xxx_ptr, gen_helper_vfmax_d) +-TRANS(xvfmin_s, LASX, gen_xxx_ptr, gen_helper_vfmin_s) +-TRANS(xvfmin_d, LASX, gen_xxx_ptr, gen_helper_vfmin_d) +- +-TRANS(vfmaxa_s, LSX, gen_vvv_ptr, gen_helper_vfmaxa_s) +-TRANS(vfmaxa_d, LSX, gen_vvv_ptr, gen_helper_vfmaxa_d) +-TRANS(vfmina_s, LSX, gen_vvv_ptr, gen_helper_vfmina_s) +-TRANS(vfmina_d, LSX, gen_vvv_ptr, gen_helper_vfmina_d) +-TRANS(xvfmaxa_s, LASX, gen_xxx_ptr, gen_helper_vfmaxa_s) +-TRANS(xvfmaxa_d, LASX, gen_xxx_ptr, gen_helper_vfmaxa_d) +-TRANS(xvfmina_s, LASX, gen_xxx_ptr, gen_helper_vfmina_s) +-TRANS(xvfmina_d, LASX, gen_xxx_ptr, gen_helper_vfmina_d) +- +-TRANS(vflogb_s, LSX, gen_vv_ptr, gen_helper_vflogb_s) +-TRANS(vflogb_d, LSX, gen_vv_ptr, gen_helper_vflogb_d) +-TRANS(xvflogb_s, LASX, gen_xx_ptr, gen_helper_vflogb_s) +-TRANS(xvflogb_d, LASX, gen_xx_ptr, gen_helper_vflogb_d) +- +-TRANS(vfclass_s, LSX, gen_vv_ptr, gen_helper_vfclass_s) +-TRANS(vfclass_d, LSX, gen_vv_ptr, gen_helper_vfclass_d) +-TRANS(xvfclass_s, LASX, gen_xx_ptr, gen_helper_vfclass_s) +-TRANS(xvfclass_d, LASX, gen_xx_ptr, gen_helper_vfclass_d) +- +-TRANS(vfsqrt_s, LSX, gen_vv_ptr, gen_helper_vfsqrt_s) +-TRANS(vfsqrt_d, LSX, gen_vv_ptr, gen_helper_vfsqrt_d) +-TRANS(vfrecip_s, LSX, gen_vv_ptr, gen_helper_vfrecip_s) +-TRANS(vfrecip_d, LSX, gen_vv_ptr, gen_helper_vfrecip_d) +-TRANS(vfrsqrt_s, LSX, gen_vv_ptr, gen_helper_vfrsqrt_s) +-TRANS(vfrsqrt_d, LSX, gen_vv_ptr, gen_helper_vfrsqrt_d) +-TRANS(xvfsqrt_s, LASX, gen_xx_ptr, gen_helper_vfsqrt_s) +-TRANS(xvfsqrt_d, LASX, gen_xx_ptr, gen_helper_vfsqrt_d) +-TRANS(xvfrecip_s, LASX, gen_xx_ptr, gen_helper_vfrecip_s) +-TRANS(xvfrecip_d, LASX, gen_xx_ptr, gen_helper_vfrecip_d) +-TRANS(xvfrsqrt_s, LASX, gen_xx_ptr, gen_helper_vfrsqrt_s) +-TRANS(xvfrsqrt_d, LASX, gen_xx_ptr, gen_helper_vfrsqrt_d) +- +-TRANS(vfcvtl_s_h, LSX, gen_vv_ptr, gen_helper_vfcvtl_s_h) +-TRANS(vfcvth_s_h, LSX, gen_vv_ptr, gen_helper_vfcvth_s_h) +-TRANS(vfcvtl_d_s, LSX, gen_vv_ptr, gen_helper_vfcvtl_d_s) +-TRANS(vfcvth_d_s, LSX, gen_vv_ptr, gen_helper_vfcvth_d_s) +-TRANS(vfcvt_h_s, LSX, gen_vvv_ptr, gen_helper_vfcvt_h_s) +-TRANS(vfcvt_s_d, LSX, gen_vvv_ptr, gen_helper_vfcvt_s_d) +-TRANS(xvfcvtl_s_h, LASX, gen_xx_ptr, gen_helper_vfcvtl_s_h) +-TRANS(xvfcvth_s_h, LASX, gen_xx_ptr, gen_helper_vfcvth_s_h) +-TRANS(xvfcvtl_d_s, LASX, gen_xx_ptr, gen_helper_vfcvtl_d_s) +-TRANS(xvfcvth_d_s, LASX, gen_xx_ptr, gen_helper_vfcvth_d_s) +-TRANS(xvfcvt_h_s, LASX, gen_xxx_ptr, gen_helper_vfcvt_h_s) +-TRANS(xvfcvt_s_d, LASX, gen_xxx_ptr, gen_helper_vfcvt_s_d) +- +-TRANS(vfrintrne_s, LSX, gen_vv_ptr, gen_helper_vfrintrne_s) +-TRANS(vfrintrne_d, LSX, gen_vv_ptr, gen_helper_vfrintrne_d) +-TRANS(vfrintrz_s, LSX, gen_vv_ptr, gen_helper_vfrintrz_s) +-TRANS(vfrintrz_d, LSX, gen_vv_ptr, gen_helper_vfrintrz_d) +-TRANS(vfrintrp_s, LSX, gen_vv_ptr, gen_helper_vfrintrp_s) +-TRANS(vfrintrp_d, LSX, gen_vv_ptr, gen_helper_vfrintrp_d) +-TRANS(vfrintrm_s, LSX, gen_vv_ptr, gen_helper_vfrintrm_s) +-TRANS(vfrintrm_d, LSX, gen_vv_ptr, gen_helper_vfrintrm_d) +-TRANS(vfrint_s, LSX, gen_vv_ptr, gen_helper_vfrint_s) +-TRANS(vfrint_d, LSX, gen_vv_ptr, gen_helper_vfrint_d) +-TRANS(xvfrintrne_s, LASX, gen_xx_ptr, gen_helper_vfrintrne_s) +-TRANS(xvfrintrne_d, LASX, gen_xx_ptr, gen_helper_vfrintrne_d) +-TRANS(xvfrintrz_s, LASX, gen_xx_ptr, gen_helper_vfrintrz_s) +-TRANS(xvfrintrz_d, LASX, gen_xx_ptr, gen_helper_vfrintrz_d) +-TRANS(xvfrintrp_s, LASX, gen_xx_ptr, gen_helper_vfrintrp_s) +-TRANS(xvfrintrp_d, LASX, gen_xx_ptr, gen_helper_vfrintrp_d) +-TRANS(xvfrintrm_s, LASX, gen_xx_ptr, gen_helper_vfrintrm_s) +-TRANS(xvfrintrm_d, LASX, gen_xx_ptr, gen_helper_vfrintrm_d) +-TRANS(xvfrint_s, LASX, gen_xx_ptr, gen_helper_vfrint_s) +-TRANS(xvfrint_d, LASX, gen_xx_ptr, gen_helper_vfrint_d) +- +-TRANS(vftintrne_w_s, LSX, gen_vv_ptr, gen_helper_vftintrne_w_s) +-TRANS(vftintrne_l_d, LSX, gen_vv_ptr, gen_helper_vftintrne_l_d) +-TRANS(vftintrz_w_s, LSX, gen_vv_ptr, gen_helper_vftintrz_w_s) +-TRANS(vftintrz_l_d, LSX, gen_vv_ptr, gen_helper_vftintrz_l_d) +-TRANS(vftintrp_w_s, LSX, gen_vv_ptr, gen_helper_vftintrp_w_s) +-TRANS(vftintrp_l_d, LSX, gen_vv_ptr, gen_helper_vftintrp_l_d) +-TRANS(vftintrm_w_s, LSX, gen_vv_ptr, gen_helper_vftintrm_w_s) +-TRANS(vftintrm_l_d, LSX, gen_vv_ptr, gen_helper_vftintrm_l_d) +-TRANS(vftint_w_s, LSX, gen_vv_ptr, gen_helper_vftint_w_s) +-TRANS(vftint_l_d, LSX, gen_vv_ptr, gen_helper_vftint_l_d) +-TRANS(vftintrz_wu_s, LSX, gen_vv_ptr, gen_helper_vftintrz_wu_s) +-TRANS(vftintrz_lu_d, LSX, gen_vv_ptr, gen_helper_vftintrz_lu_d) +-TRANS(vftint_wu_s, LSX, gen_vv_ptr, gen_helper_vftint_wu_s) +-TRANS(vftint_lu_d, LSX, gen_vv_ptr, gen_helper_vftint_lu_d) +-TRANS(vftintrne_w_d, LSX, gen_vvv_ptr, gen_helper_vftintrne_w_d) +-TRANS(vftintrz_w_d, LSX, gen_vvv_ptr, gen_helper_vftintrz_w_d) +-TRANS(vftintrp_w_d, LSX, gen_vvv_ptr, gen_helper_vftintrp_w_d) +-TRANS(vftintrm_w_d, LSX, gen_vvv_ptr, gen_helper_vftintrm_w_d) +-TRANS(vftint_w_d, LSX, gen_vvv_ptr, gen_helper_vftint_w_d) +-TRANS(vftintrnel_l_s, LSX, gen_vv_ptr, gen_helper_vftintrnel_l_s) +-TRANS(vftintrneh_l_s, LSX, gen_vv_ptr, gen_helper_vftintrneh_l_s) +-TRANS(vftintrzl_l_s, LSX, gen_vv_ptr, gen_helper_vftintrzl_l_s) +-TRANS(vftintrzh_l_s, LSX, gen_vv_ptr, gen_helper_vftintrzh_l_s) +-TRANS(vftintrpl_l_s, LSX, gen_vv_ptr, gen_helper_vftintrpl_l_s) +-TRANS(vftintrph_l_s, LSX, gen_vv_ptr, gen_helper_vftintrph_l_s) +-TRANS(vftintrml_l_s, LSX, gen_vv_ptr, gen_helper_vftintrml_l_s) +-TRANS(vftintrmh_l_s, LSX, gen_vv_ptr, gen_helper_vftintrmh_l_s) +-TRANS(vftintl_l_s, LSX, gen_vv_ptr, gen_helper_vftintl_l_s) +-TRANS(vftinth_l_s, LSX, gen_vv_ptr, gen_helper_vftinth_l_s) +-TRANS(xvftintrne_w_s, LASX, gen_xx_ptr, gen_helper_vftintrne_w_s) +-TRANS(xvftintrne_l_d, LASX, gen_xx_ptr, gen_helper_vftintrne_l_d) +-TRANS(xvftintrz_w_s, LASX, gen_xx_ptr, gen_helper_vftintrz_w_s) +-TRANS(xvftintrz_l_d, LASX, gen_xx_ptr, gen_helper_vftintrz_l_d) +-TRANS(xvftintrp_w_s, LASX, gen_xx_ptr, gen_helper_vftintrp_w_s) +-TRANS(xvftintrp_l_d, LASX, gen_xx_ptr, gen_helper_vftintrp_l_d) +-TRANS(xvftintrm_w_s, LASX, gen_xx_ptr, gen_helper_vftintrm_w_s) +-TRANS(xvftintrm_l_d, LASX, gen_xx_ptr, gen_helper_vftintrm_l_d) +-TRANS(xvftint_w_s, LASX, gen_xx_ptr, gen_helper_vftint_w_s) +-TRANS(xvftint_l_d, LASX, gen_xx_ptr, gen_helper_vftint_l_d) +-TRANS(xvftintrz_wu_s, LASX, gen_xx_ptr, gen_helper_vftintrz_wu_s) +-TRANS(xvftintrz_lu_d, LASX, gen_xx_ptr, gen_helper_vftintrz_lu_d) +-TRANS(xvftint_wu_s, LASX, gen_xx_ptr, gen_helper_vftint_wu_s) +-TRANS(xvftint_lu_d, LASX, gen_xx_ptr, gen_helper_vftint_lu_d) +-TRANS(xvftintrne_w_d, LASX, gen_xxx_ptr, gen_helper_vftintrne_w_d) +-TRANS(xvftintrz_w_d, LASX, gen_xxx_ptr, gen_helper_vftintrz_w_d) +-TRANS(xvftintrp_w_d, LASX, gen_xxx_ptr, gen_helper_vftintrp_w_d) +-TRANS(xvftintrm_w_d, LASX, gen_xxx_ptr, gen_helper_vftintrm_w_d) +-TRANS(xvftint_w_d, LASX, gen_xxx_ptr, gen_helper_vftint_w_d) +-TRANS(xvftintrnel_l_s, LASX, gen_xx_ptr, gen_helper_vftintrnel_l_s) +-TRANS(xvftintrneh_l_s, LASX, gen_xx_ptr, gen_helper_vftintrneh_l_s) +-TRANS(xvftintrzl_l_s, LASX, gen_xx_ptr, gen_helper_vftintrzl_l_s) +-TRANS(xvftintrzh_l_s, LASX, gen_xx_ptr, gen_helper_vftintrzh_l_s) +-TRANS(xvftintrpl_l_s, LASX, gen_xx_ptr, gen_helper_vftintrpl_l_s) +-TRANS(xvftintrph_l_s, LASX, gen_xx_ptr, gen_helper_vftintrph_l_s) +-TRANS(xvftintrml_l_s, LASX, gen_xx_ptr, gen_helper_vftintrml_l_s) +-TRANS(xvftintrmh_l_s, LASX, gen_xx_ptr, gen_helper_vftintrmh_l_s) +-TRANS(xvftintl_l_s, LASX, gen_xx_ptr, gen_helper_vftintl_l_s) +-TRANS(xvftinth_l_s, LASX, gen_xx_ptr, gen_helper_vftinth_l_s) +- +-TRANS(vffint_s_w, LSX, gen_vv_ptr, gen_helper_vffint_s_w) +-TRANS(vffint_d_l, LSX, gen_vv_ptr, gen_helper_vffint_d_l) +-TRANS(vffint_s_wu, LSX, gen_vv_ptr, gen_helper_vffint_s_wu) +-TRANS(vffint_d_lu, LSX, gen_vv_ptr, gen_helper_vffint_d_lu) +-TRANS(vffintl_d_w, LSX, gen_vv_ptr, gen_helper_vffintl_d_w) +-TRANS(vffinth_d_w, LSX, gen_vv_ptr, gen_helper_vffinth_d_w) +-TRANS(vffint_s_l, LSX, gen_vvv_ptr, gen_helper_vffint_s_l) +-TRANS(xvffint_s_w, LASX, gen_xx_ptr, gen_helper_vffint_s_w) +-TRANS(xvffint_d_l, LASX, gen_xx_ptr, gen_helper_vffint_d_l) +-TRANS(xvffint_s_wu, LASX, gen_xx_ptr, gen_helper_vffint_s_wu) +-TRANS(xvffint_d_lu, LASX, gen_xx_ptr, gen_helper_vffint_d_lu) +-TRANS(xvffintl_d_w, LASX, gen_xx_ptr, gen_helper_vffintl_d_w) +-TRANS(xvffinth_d_w, LASX, gen_xx_ptr, gen_helper_vffinth_d_w) +-TRANS(xvffint_s_l, LASX, gen_xxx_ptr, gen_helper_vffint_s_l) +- +-static bool do_cmp_vl(DisasContext *ctx, arg_vvv *a, +- uint32_t oprsz, MemOp mop, TCGCond cond) +-{ +- uint32_t vd_ofs, vj_ofs, vk_ofs; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- vd_ofs = vec_full_offset(a->vd); +- vj_ofs = vec_full_offset(a->vj); +- vk_ofs = vec_full_offset(a->vk); +- +- tcg_gen_gvec_cmp(cond, mop, vd_ofs, vj_ofs, vk_ofs, oprsz, ctx->vl / 8); +- return true; +-} +- +-static bool do_cmp(DisasContext *ctx, arg_vvv *a, +- MemOp mop, TCGCond cond) +-{ +- return do_cmp_vl(ctx, a, 16, mop, cond); +-} +- +-static bool do_xcmp(DisasContext *ctx, arg_vvv *a, +- MemOp mop, TCGCond cond) +-{ +- return do_cmp_vl(ctx, a, 32, mop, cond); +-} +- +-static bool do_cmpi_vl(DisasContext *ctx, arg_vv_i *a, +- uint32_t oprsz, MemOp mop, TCGCond cond) +-{ +- uint32_t vd_ofs, vj_ofs; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- vd_ofs = vec_full_offset(a->vd); +- vj_ofs = vec_full_offset(a->vj); +- +- tcg_gen_gvec_cmpi(cond, mop, vd_ofs, vj_ofs, a->imm, oprsz, ctx->vl / 8); +- return true; +-} +- +-static bool do_cmpi(DisasContext *ctx, arg_vv_i *a, +- MemOp mop, TCGCond cond) +-{ +- return do_cmpi_vl(ctx, a, 16, mop, cond); +-} +- +-static bool do_xcmpi(DisasContext *ctx, arg_vv_i *a, +- MemOp mop, TCGCond cond) +-{ +- return do_cmpi_vl(ctx, a, 32, mop, cond); +-} +- +-TRANS(vseq_b, LSX, do_cmp, MO_8, TCG_COND_EQ) +-TRANS(vseq_h, LSX, do_cmp, MO_16, TCG_COND_EQ) +-TRANS(vseq_w, LSX, do_cmp, MO_32, TCG_COND_EQ) +-TRANS(vseq_d, LSX, do_cmp, MO_64, TCG_COND_EQ) +-TRANS(vseqi_b, LSX, do_cmpi, MO_8, TCG_COND_EQ) +-TRANS(vseqi_h, LSX, do_cmpi, MO_16, TCG_COND_EQ) +-TRANS(vseqi_w, LSX, do_cmpi, MO_32, TCG_COND_EQ) +-TRANS(vseqi_d, LSX, do_cmpi, MO_64, TCG_COND_EQ) +-TRANS(xvseq_b, LASX, do_xcmp, MO_8, TCG_COND_EQ) +-TRANS(xvseq_h, LASX, do_xcmp, MO_16, TCG_COND_EQ) +-TRANS(xvseq_w, LASX, do_xcmp, MO_32, TCG_COND_EQ) +-TRANS(xvseq_d, LASX, do_xcmp, MO_64, TCG_COND_EQ) +-TRANS(xvseqi_b, LASX, do_xcmpi, MO_8, TCG_COND_EQ) +-TRANS(xvseqi_h, LASX, do_xcmpi, MO_16, TCG_COND_EQ) +-TRANS(xvseqi_w, LASX, do_xcmpi, MO_32, TCG_COND_EQ) +-TRANS(xvseqi_d, LASX, do_xcmpi, MO_64, TCG_COND_EQ) +- +-TRANS(vsle_b, LSX, do_cmp, MO_8, TCG_COND_LE) +-TRANS(vsle_h, LSX, do_cmp, MO_16, TCG_COND_LE) +-TRANS(vsle_w, LSX, do_cmp, MO_32, TCG_COND_LE) +-TRANS(vsle_d, LSX, do_cmp, MO_64, TCG_COND_LE) +-TRANS(vslei_b, LSX, do_cmpi, MO_8, TCG_COND_LE) +-TRANS(vslei_h, LSX, do_cmpi, MO_16, TCG_COND_LE) +-TRANS(vslei_w, LSX, do_cmpi, MO_32, TCG_COND_LE) +-TRANS(vslei_d, LSX, do_cmpi, MO_64, TCG_COND_LE) +-TRANS(vsle_bu, LSX, do_cmp, MO_8, TCG_COND_LEU) +-TRANS(vsle_hu, LSX, do_cmp, MO_16, TCG_COND_LEU) +-TRANS(vsle_wu, LSX, do_cmp, MO_32, TCG_COND_LEU) +-TRANS(vsle_du, LSX, do_cmp, MO_64, TCG_COND_LEU) +-TRANS(vslei_bu, LSX, do_cmpi, MO_8, TCG_COND_LEU) +-TRANS(vslei_hu, LSX, do_cmpi, MO_16, TCG_COND_LEU) +-TRANS(vslei_wu, LSX, do_cmpi, MO_32, TCG_COND_LEU) +-TRANS(vslei_du, LSX, do_cmpi, MO_64, TCG_COND_LEU) +-TRANS(xvsle_b, LASX, do_xcmp, MO_8, TCG_COND_LE) +-TRANS(xvsle_h, LASX, do_xcmp, MO_16, TCG_COND_LE) +-TRANS(xvsle_w, LASX, do_xcmp, MO_32, TCG_COND_LE) +-TRANS(xvsle_d, LASX, do_xcmp, MO_64, TCG_COND_LE) +-TRANS(xvslei_b, LASX, do_xcmpi, MO_8, TCG_COND_LE) +-TRANS(xvslei_h, LASX, do_xcmpi, MO_16, TCG_COND_LE) +-TRANS(xvslei_w, LASX, do_xcmpi, MO_32, TCG_COND_LE) +-TRANS(xvslei_d, LASX, do_xcmpi, MO_64, TCG_COND_LE) +-TRANS(xvsle_bu, LASX, do_xcmp, MO_8, TCG_COND_LEU) +-TRANS(xvsle_hu, LASX, do_xcmp, MO_16, TCG_COND_LEU) +-TRANS(xvsle_wu, LASX, do_xcmp, MO_32, TCG_COND_LEU) +-TRANS(xvsle_du, LASX, do_xcmp, MO_64, TCG_COND_LEU) +-TRANS(xvslei_bu, LASX, do_xcmpi, MO_8, TCG_COND_LEU) +-TRANS(xvslei_hu, LASX, do_xcmpi, MO_16, TCG_COND_LEU) +-TRANS(xvslei_wu, LASX, do_xcmpi, MO_32, TCG_COND_LEU) +-TRANS(xvslei_du, LASX, do_xcmpi, MO_64, TCG_COND_LEU) +- +-TRANS(vslt_b, LSX, do_cmp, MO_8, TCG_COND_LT) +-TRANS(vslt_h, LSX, do_cmp, MO_16, TCG_COND_LT) +-TRANS(vslt_w, LSX, do_cmp, MO_32, TCG_COND_LT) +-TRANS(vslt_d, LSX, do_cmp, MO_64, TCG_COND_LT) +-TRANS(vslti_b, LSX, do_cmpi, MO_8, TCG_COND_LT) +-TRANS(vslti_h, LSX, do_cmpi, MO_16, TCG_COND_LT) +-TRANS(vslti_w, LSX, do_cmpi, MO_32, TCG_COND_LT) +-TRANS(vslti_d, LSX, do_cmpi, MO_64, TCG_COND_LT) +-TRANS(vslt_bu, LSX, do_cmp, MO_8, TCG_COND_LTU) +-TRANS(vslt_hu, LSX, do_cmp, MO_16, TCG_COND_LTU) +-TRANS(vslt_wu, LSX, do_cmp, MO_32, TCG_COND_LTU) +-TRANS(vslt_du, LSX, do_cmp, MO_64, TCG_COND_LTU) +-TRANS(vslti_bu, LSX, do_cmpi, MO_8, TCG_COND_LTU) +-TRANS(vslti_hu, LSX, do_cmpi, MO_16, TCG_COND_LTU) +-TRANS(vslti_wu, LSX, do_cmpi, MO_32, TCG_COND_LTU) +-TRANS(vslti_du, LSX, do_cmpi, MO_64, TCG_COND_LTU) +-TRANS(xvslt_b, LASX, do_xcmp, MO_8, TCG_COND_LT) +-TRANS(xvslt_h, LASX, do_xcmp, MO_16, TCG_COND_LT) +-TRANS(xvslt_w, LASX, do_xcmp, MO_32, TCG_COND_LT) +-TRANS(xvslt_d, LASX, do_xcmp, MO_64, TCG_COND_LT) +-TRANS(xvslti_b, LASX, do_xcmpi, MO_8, TCG_COND_LT) +-TRANS(xvslti_h, LASX, do_xcmpi, MO_16, TCG_COND_LT) +-TRANS(xvslti_w, LASX, do_xcmpi, MO_32, TCG_COND_LT) +-TRANS(xvslti_d, LASX, do_xcmpi, MO_64, TCG_COND_LT) +-TRANS(xvslt_bu, LASX, do_xcmp, MO_8, TCG_COND_LTU) +-TRANS(xvslt_hu, LASX, do_xcmp, MO_16, TCG_COND_LTU) +-TRANS(xvslt_wu, LASX, do_xcmp, MO_32, TCG_COND_LTU) +-TRANS(xvslt_du, LASX, do_xcmp, MO_64, TCG_COND_LTU) +-TRANS(xvslti_bu, LASX, do_xcmpi, MO_8, TCG_COND_LTU) +-TRANS(xvslti_hu, LASX, do_xcmpi, MO_16, TCG_COND_LTU) +-TRANS(xvslti_wu, LASX, do_xcmpi, MO_32, TCG_COND_LTU) +-TRANS(xvslti_du, LASX, do_xcmpi, MO_64, TCG_COND_LTU) +- +-static bool do_vfcmp_cond_s(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz) +-{ +- uint32_t flags; +- void (*fn)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32); +- TCGv_i32 vd = tcg_constant_i32(a->vd); +- TCGv_i32 vj = tcg_constant_i32(a->vj); +- TCGv_i32 vk = tcg_constant_i32(a->vk); +- TCGv_i32 oprsz = tcg_constant_i32(sz); +- +- if (!check_vec(ctx, sz)) { +- return true; +- } +- +- fn = (a->fcond & 1 ? gen_helper_vfcmp_s_s : gen_helper_vfcmp_c_s); +- flags = get_fcmp_flags(a->fcond >> 1); +- fn(tcg_env, oprsz, vd, vj, vk, tcg_constant_i32(flags)); +- +- return true; +-} +- +-static bool do_vfcmp_cond_d(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz) +-{ +- uint32_t flags; +- void (*fn)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32); +- TCGv_i32 vd = tcg_constant_i32(a->vd); +- TCGv_i32 vj = tcg_constant_i32(a->vj); +- TCGv_i32 vk = tcg_constant_i32(a->vk); +- TCGv_i32 oprsz = tcg_constant_i32(sz); +- +- if (!check_vec(ctx, sz)) { +- return true; +- } +- +- fn = (a->fcond & 1 ? gen_helper_vfcmp_s_d : gen_helper_vfcmp_c_d); +- flags = get_fcmp_flags(a->fcond >> 1); +- fn(tcg_env, oprsz, vd, vj, vk, tcg_constant_i32(flags)); +- +- return true; +-} +- +-TRANS(vfcmp_cond_s, LSX, do_vfcmp_cond_s, 16) +-TRANS(vfcmp_cond_d, LSX, do_vfcmp_cond_d, 16) +-TRANS(xvfcmp_cond_s, LASX, do_vfcmp_cond_s, 32) +-TRANS(xvfcmp_cond_d, LASX, do_vfcmp_cond_d, 32) +- +-static bool do_vbitsel_v(DisasContext *ctx, arg_vvvv *a, uint32_t oprsz) +-{ +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_gvec_bitsel(MO_64, vec_full_offset(a->vd), vec_full_offset(a->va), +- vec_full_offset(a->vk), vec_full_offset(a->vj), +- oprsz, ctx->vl / 8); +- return true; +-} +- +-TRANS(vbitsel_v, LSX, do_vbitsel_v, 16) +-TRANS(xvbitsel_v, LASX, do_vbitsel_v, 32) +- +-static void gen_vbitseli(unsigned vece, TCGv_vec a, TCGv_vec b, int64_t imm) +-{ +- tcg_gen_bitsel_vec(vece, a, a, tcg_constant_vec_matching(a, vece, imm), b); +-} +- +-static bool do_vbitseli_b(DisasContext *ctx, arg_vv_i *a, uint32_t oprsz) +-{ +- static const GVecGen2i op = { +- .fniv = gen_vbitseli, +- .fnoi = gen_helper_vbitseli_b, +- .vece = MO_8, +- .load_dest = true +- }; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_gvec_2i(vec_full_offset(a->vd), vec_full_offset(a->vj), +- oprsz, ctx->vl / 8, a->imm , &op); +- return true; +-} +- +-TRANS(vbitseli_b, LSX, do_vbitseli_b, 16) +-TRANS(xvbitseli_b, LASX, do_vbitseli_b, 32) +- +-#define VSET(NAME, COND) \ +-static bool trans_## NAME (DisasContext *ctx, arg_cv *a) \ +-{ \ +- TCGv_i64 t1, al, ah; \ +- \ +- al = tcg_temp_new_i64(); \ +- ah = tcg_temp_new_i64(); \ +- t1 = tcg_temp_new_i64(); \ +- \ +- get_vreg64(ah, a->vj, 1); \ +- get_vreg64(al, a->vj, 0); \ +- \ +- if (!avail_LSX(ctx)) { \ +- return false; \ +- } \ +- \ +- if (!check_vec(ctx, 16)) { \ +- return true; \ +- } \ +- \ +- tcg_gen_or_i64(t1, al, ah); \ +- tcg_gen_setcondi_i64(COND, t1, t1, 0); \ +- tcg_gen_st8_tl(t1, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); \ +- \ +- return true; \ +-} +- +-VSET(vseteqz_v, TCG_COND_EQ) +-VSET(vsetnez_v, TCG_COND_NE) +- +-TRANS(vsetanyeqz_b, LSX, gen_cv, gen_helper_vsetanyeqz_b) +-TRANS(vsetanyeqz_h, LSX, gen_cv, gen_helper_vsetanyeqz_h) +-TRANS(vsetanyeqz_w, LSX, gen_cv, gen_helper_vsetanyeqz_w) +-TRANS(vsetanyeqz_d, LSX, gen_cv, gen_helper_vsetanyeqz_d) +-TRANS(vsetallnez_b, LSX, gen_cv, gen_helper_vsetallnez_b) +-TRANS(vsetallnez_h, LSX, gen_cv, gen_helper_vsetallnez_h) +-TRANS(vsetallnez_w, LSX, gen_cv, gen_helper_vsetallnez_w) +-TRANS(vsetallnez_d, LSX, gen_cv, gen_helper_vsetallnez_d) +- +-#define XVSET(NAME, COND) \ +-static bool trans_## NAME(DisasContext *ctx, arg_cv * a) \ +-{ \ +- TCGv_i64 t1, t2, d[4]; \ +- \ +- d[0] = tcg_temp_new_i64(); \ +- d[1] = tcg_temp_new_i64(); \ +- d[2] = tcg_temp_new_i64(); \ +- d[3] = tcg_temp_new_i64(); \ +- t1 = tcg_temp_new_i64(); \ +- t2 = tcg_temp_new_i64(); \ +- \ +- get_vreg64(d[0], a->vj, 0); \ +- get_vreg64(d[1], a->vj, 1); \ +- get_vreg64(d[2], a->vj, 2); \ +- get_vreg64(d[3], a->vj, 3); \ +- \ +- if (!avail_LASX(ctx)) { \ +- return false; \ +- } \ +- \ +- if (!check_vec(ctx, 32)) { \ +- return true; \ +- } \ +- \ +- tcg_gen_or_i64(t1, d[0], d[1]); \ +- tcg_gen_or_i64(t2, d[2], d[3]); \ +- tcg_gen_or_i64(t1, t2, t1); \ +- tcg_gen_setcondi_i64(COND, t1, t1, 0); \ +- tcg_gen_st8_tl(t1, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); \ +- \ +- return true; \ +-} +- +-XVSET(xvseteqz_v, TCG_COND_EQ) +-XVSET(xvsetnez_v, TCG_COND_NE) +- +-TRANS(xvsetanyeqz_b, LASX, gen_cx, gen_helper_vsetanyeqz_b) +-TRANS(xvsetanyeqz_h, LASX, gen_cx, gen_helper_vsetanyeqz_h) +-TRANS(xvsetanyeqz_w, LASX, gen_cx, gen_helper_vsetanyeqz_w) +-TRANS(xvsetanyeqz_d, LASX, gen_cx, gen_helper_vsetanyeqz_d) +-TRANS(xvsetallnez_b, LASX, gen_cx, gen_helper_vsetallnez_b) +-TRANS(xvsetallnez_h, LASX, gen_cx, gen_helper_vsetallnez_h) +-TRANS(xvsetallnez_w, LASX, gen_cx, gen_helper_vsetallnez_w) +-TRANS(xvsetallnez_d, LASX, gen_cx, gen_helper_vsetallnez_d) +- +-static bool gen_g2v_vl(DisasContext *ctx, arg_vr_i *a, uint32_t oprsz, MemOp mop, +- void (*func)(TCGv, TCGv_ptr, tcg_target_long)) +-{ +- TCGv src = gpr_src(ctx, a->rj, EXT_NONE); +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- func(src, tcg_env, vec_reg_offset(a->vd, a->imm, mop)); +- +- return true; +-} +- +-static bool gen_g2v(DisasContext *ctx, arg_vr_i *a, MemOp mop, +- void (*func)(TCGv, TCGv_ptr, tcg_target_long)) +-{ +- return gen_g2v_vl(ctx, a, 16, mop, func); +-} +- +-static bool gen_g2x(DisasContext *ctx, arg_vr_i *a, MemOp mop, +- void (*func)(TCGv, TCGv_ptr, tcg_target_long)) +-{ +- return gen_g2v_vl(ctx, a, 32, mop, func); +-} +- +-TRANS(vinsgr2vr_b, LSX, gen_g2v, MO_8, tcg_gen_st8_i64) +-TRANS(vinsgr2vr_h, LSX, gen_g2v, MO_16, tcg_gen_st16_i64) +-TRANS(vinsgr2vr_w, LSX, gen_g2v, MO_32, tcg_gen_st32_i64) +-TRANS(vinsgr2vr_d, LSX, gen_g2v, MO_64, tcg_gen_st_i64) +-TRANS(xvinsgr2vr_w, LASX, gen_g2x, MO_32, tcg_gen_st32_i64) +-TRANS(xvinsgr2vr_d, LASX, gen_g2x, MO_64, tcg_gen_st_i64) +- +-static bool gen_v2g_vl(DisasContext *ctx, arg_rv_i *a, uint32_t oprsz, MemOp mop, +- void (*func)(TCGv, TCGv_ptr, tcg_target_long)) +-{ +- TCGv dst = gpr_dst(ctx, a->rd, EXT_NONE); +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- func(dst, tcg_env, vec_reg_offset(a->vj, a->imm, mop)); +- +- return true; +-} +- +-static bool gen_v2g(DisasContext *ctx, arg_rv_i *a, MemOp mop, +- void (*func)(TCGv, TCGv_ptr, tcg_target_long)) +-{ +- return gen_v2g_vl(ctx, a, 16, mop, func); +-} +- +-static bool gen_x2g(DisasContext *ctx, arg_rv_i *a, MemOp mop, +- void (*func)(TCGv, TCGv_ptr, tcg_target_long)) +-{ +- return gen_v2g_vl(ctx, a, 32, mop, func); +-} +- +-TRANS(vpickve2gr_b, LSX, gen_v2g, MO_8, tcg_gen_ld8s_i64) +-TRANS(vpickve2gr_h, LSX, gen_v2g, MO_16, tcg_gen_ld16s_i64) +-TRANS(vpickve2gr_w, LSX, gen_v2g, MO_32, tcg_gen_ld32s_i64) +-TRANS(vpickve2gr_d, LSX, gen_v2g, MO_64, tcg_gen_ld_i64) +-TRANS(vpickve2gr_bu, LSX, gen_v2g, MO_8, tcg_gen_ld8u_i64) +-TRANS(vpickve2gr_hu, LSX, gen_v2g, MO_16, tcg_gen_ld16u_i64) +-TRANS(vpickve2gr_wu, LSX, gen_v2g, MO_32, tcg_gen_ld32u_i64) +-TRANS(vpickve2gr_du, LSX, gen_v2g, MO_64, tcg_gen_ld_i64) +-TRANS(xvpickve2gr_w, LASX, gen_x2g, MO_32, tcg_gen_ld32s_i64) +-TRANS(xvpickve2gr_d, LASX, gen_x2g, MO_64, tcg_gen_ld_i64) +-TRANS(xvpickve2gr_wu, LASX, gen_x2g, MO_32, tcg_gen_ld32u_i64) +-TRANS(xvpickve2gr_du, LASX, gen_x2g, MO_64, tcg_gen_ld_i64) +- +-static bool gvec_dup_vl(DisasContext *ctx, arg_vr *a, +- uint32_t oprsz, MemOp mop) +-{ +- TCGv src = gpr_src(ctx, a->rj, EXT_NONE); +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_gvec_dup_i64(mop, vec_full_offset(a->vd), +- oprsz, ctx->vl/8, src); +- return true; +-} +- +-static bool gvec_dup(DisasContext *ctx, arg_vr *a, MemOp mop) +-{ +- return gvec_dup_vl(ctx, a, 16, mop); +-} +- +-static bool gvec_dupx(DisasContext *ctx, arg_vr *a, MemOp mop) +-{ +- return gvec_dup_vl(ctx, a, 32, mop); +-} +- +-TRANS(vreplgr2vr_b, LSX, gvec_dup, MO_8) +-TRANS(vreplgr2vr_h, LSX, gvec_dup, MO_16) +-TRANS(vreplgr2vr_w, LSX, gvec_dup, MO_32) +-TRANS(vreplgr2vr_d, LSX, gvec_dup, MO_64) +-TRANS(xvreplgr2vr_b, LASX, gvec_dupx, MO_8) +-TRANS(xvreplgr2vr_h, LASX, gvec_dupx, MO_16) +-TRANS(xvreplgr2vr_w, LASX, gvec_dupx, MO_32) +-TRANS(xvreplgr2vr_d, LASX, gvec_dupx, MO_64) +- +-static bool trans_vreplvei_b(DisasContext *ctx, arg_vv_i *a) +-{ +- if (!avail_LSX(ctx)) { +- return false; +- } +- +- if (!check_vec(ctx, 16)) { +- return true; +- } +- +- tcg_gen_gvec_dup_mem(MO_8,vec_full_offset(a->vd), +- offsetof(CPULoongArchState, +- fpr[a->vj].vreg.B((a->imm))), +- 16, ctx->vl/8); +- return true; +-} +- +-static bool trans_vreplvei_h(DisasContext *ctx, arg_vv_i *a) +-{ +- if (!avail_LSX(ctx)) { +- return false; +- } +- +- if (!check_vec(ctx, 16)) { +- return true; +- } +- +- tcg_gen_gvec_dup_mem(MO_16, vec_full_offset(a->vd), +- offsetof(CPULoongArchState, +- fpr[a->vj].vreg.H((a->imm))), +- 16, ctx->vl/8); +- return true; +-} +-static bool trans_vreplvei_w(DisasContext *ctx, arg_vv_i *a) +-{ +- if (!avail_LSX(ctx)) { +- return false; +- } +- +- if (!check_vec(ctx, 16)) { +- return true; +- } +- +- tcg_gen_gvec_dup_mem(MO_32, vec_full_offset(a->vd), +- offsetof(CPULoongArchState, +- fpr[a->vj].vreg.W((a->imm))), +- 16, ctx->vl/8); +- return true; +-} +-static bool trans_vreplvei_d(DisasContext *ctx, arg_vv_i *a) +-{ +- if (!avail_LSX(ctx)) { +- return false; +- } +- +- if (!check_vec(ctx, 16)) { +- return true; +- } +- +- tcg_gen_gvec_dup_mem(MO_64, vec_full_offset(a->vd), +- offsetof(CPULoongArchState, +- fpr[a->vj].vreg.D((a->imm))), +- 16, ctx->vl/8); +- return true; +-} +- +-static bool gen_vreplve_vl(DisasContext *ctx, arg_vvr *a, +- uint32_t oprsz, int vece, int bit, +- void (*func)(TCGv_i64, TCGv_ptr, tcg_target_long)) +-{ +- int i; +- TCGv_i64 t0 = tcg_temp_new_i64(); +- TCGv_ptr t1 = tcg_temp_new_ptr(); +- TCGv_i64 t2 = tcg_temp_new_i64(); +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- tcg_gen_andi_i64(t0, gpr_src(ctx, a->rk, EXT_NONE), (LSX_LEN / bit) - 1); +- tcg_gen_shli_i64(t0, t0, vece); +- if (HOST_BIG_ENDIAN) { +- tcg_gen_xori_i64(t0, t0, vece << ((LSX_LEN / bit) - 1)); +- } +- +- tcg_gen_trunc_i64_ptr(t1, t0); +- tcg_gen_add_ptr(t1, t1, tcg_env); +- +- for (i = 0; i < oprsz; i += 16) { +- func(t2, t1, vec_full_offset(a->vj) + i); +- tcg_gen_gvec_dup_i64(vece, vec_full_offset(a->vd) + i, 16, 16, t2); +- } +- +- return true; +-} +- +-static bool gen_vreplve(DisasContext *ctx, arg_vvr *a, int vece, int bit, +- void (*func)(TCGv_i64, TCGv_ptr, tcg_target_long)) +-{ +- return gen_vreplve_vl(ctx, a, 16, vece, bit, func); +-} +- +-static bool gen_xvreplve(DisasContext *ctx, arg_vvr *a, int vece, int bit, +- void (*func)(TCGv_i64, TCGv_ptr, tcg_target_long)) +-{ +- return gen_vreplve_vl(ctx, a, 32, vece, bit, func); +-} +- +-TRANS(vreplve_b, LSX, gen_vreplve, MO_8, 8, tcg_gen_ld8u_i64) +-TRANS(vreplve_h, LSX, gen_vreplve, MO_16, 16, tcg_gen_ld16u_i64) +-TRANS(vreplve_w, LSX, gen_vreplve, MO_32, 32, tcg_gen_ld32u_i64) +-TRANS(vreplve_d, LSX, gen_vreplve, MO_64, 64, tcg_gen_ld_i64) +-TRANS(xvreplve_b, LASX, gen_xvreplve, MO_8, 8, tcg_gen_ld8u_i64) +-TRANS(xvreplve_h, LASX, gen_xvreplve, MO_16, 16, tcg_gen_ld16u_i64) +-TRANS(xvreplve_w, LASX, gen_xvreplve, MO_32, 32, tcg_gen_ld32u_i64) +-TRANS(xvreplve_d, LASX, gen_xvreplve, MO_64, 64, tcg_gen_ld_i64) +- +-static bool gen_xvrepl128(DisasContext *ctx, arg_vv_i *a, MemOp mop) +-{ +- int i; +- +- if (!check_vec(ctx, 32)) { +- return true; +- } +- +- for (i = 0; i < 32; i += 16) { +- tcg_gen_gvec_dup_mem(mop, vec_full_offset(a->vd) + i, +- vec_reg_offset(a->vj, a->imm, mop) + i, 16, 16); +- +- } +- return true; +-} +- +-TRANS(xvrepl128vei_b, LASX, gen_xvrepl128, MO_8) +-TRANS(xvrepl128vei_h, LASX, gen_xvrepl128, MO_16) +-TRANS(xvrepl128vei_w, LASX, gen_xvrepl128, MO_32) +-TRANS(xvrepl128vei_d, LASX, gen_xvrepl128, MO_64) +- +-static bool gen_xvreplve0(DisasContext *ctx, arg_vv *a, MemOp mop) +-{ +- if (!check_vec(ctx, 32)) { +- return true; +- } +- +- tcg_gen_gvec_dup_mem(mop, vec_full_offset(a->vd), +- vec_full_offset(a->vj), 32, 32); +- return true; +-} +- +-TRANS(xvreplve0_b, LASX, gen_xvreplve0, MO_8) +-TRANS(xvreplve0_h, LASX, gen_xvreplve0, MO_16) +-TRANS(xvreplve0_w, LASX, gen_xvreplve0, MO_32) +-TRANS(xvreplve0_d, LASX, gen_xvreplve0, MO_64) +-TRANS(xvreplve0_q, LASX, gen_xvreplve0, MO_128) +- +-TRANS(xvinsve0_w, LASX, gen_xx_i, gen_helper_xvinsve0_w) +-TRANS(xvinsve0_d, LASX, gen_xx_i, gen_helper_xvinsve0_d) +- +-TRANS(xvpickve_w, LASX, gen_xx_i, gen_helper_xvpickve_w) +-TRANS(xvpickve_d, LASX, gen_xx_i, gen_helper_xvpickve_d) +- +-static bool do_vbsll_v(DisasContext *ctx, arg_vv_i *a, uint32_t oprsz) +-{ +- int i, ofs; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- for (i = 0; i < oprsz / 16; i++) { +- TCGv desthigh = tcg_temp_new_i64(); +- TCGv destlow = tcg_temp_new_i64(); +- TCGv high = tcg_temp_new_i64(); +- TCGv low = tcg_temp_new_i64(); +- +- get_vreg64(low, a->vj, 2 * i); +- +- ofs = ((a->imm) & 0xf) * 8; +- if (ofs < 64) { +- get_vreg64(high, a->vj, 2 * i + 1); +- tcg_gen_extract2_i64(desthigh, low, high, 64 - ofs); +- tcg_gen_shli_i64(destlow, low, ofs); +- } else { +- tcg_gen_shli_i64(desthigh, low, ofs - 64); +- destlow = tcg_constant_i64(0); +- } +- set_vreg64(desthigh, a->vd, 2 * i + 1); +- set_vreg64(destlow, a->vd, 2 * i); +- } +- +- return true; +-} +- +-static bool do_vbsrl_v(DisasContext *ctx, arg_vv_i *a, uint32_t oprsz) +-{ +- int i, ofs; +- +- if (!check_vec(ctx, 32)) { +- return true; +- } +- +- for (i = 0; i < oprsz / 16; i++) { +- TCGv desthigh = tcg_temp_new_i64(); +- TCGv destlow = tcg_temp_new_i64(); +- TCGv high = tcg_temp_new_i64(); +- TCGv low = tcg_temp_new_i64(); +- get_vreg64(high, a->vj, 2 * i + 1); +- +- ofs = ((a->imm) & 0xf) * 8; +- if (ofs < 64) { +- get_vreg64(low, a->vj, 2 * i); +- tcg_gen_extract2_i64(destlow, low, high, ofs); +- tcg_gen_shri_i64(desthigh, high, ofs); +- } else { +- tcg_gen_shri_i64(destlow, high, ofs - 64); +- desthigh = tcg_constant_i64(0); +- } +- set_vreg64(desthigh, a->vd, 2 * i + 1); +- set_vreg64(destlow, a->vd, 2 * i); +- } +- +- return true; +-} +- +-TRANS(vbsll_v, LSX, do_vbsll_v, 16) +-TRANS(vbsrl_v, LSX, do_vbsrl_v, 16) +-TRANS(xvbsll_v, LASX, do_vbsll_v, 32) +-TRANS(xvbsrl_v, LASX, do_vbsrl_v, 32) +- +-TRANS(vpackev_b, LSX, gen_vvv, gen_helper_vpackev_b) +-TRANS(vpackev_h, LSX, gen_vvv, gen_helper_vpackev_h) +-TRANS(vpackev_w, LSX, gen_vvv, gen_helper_vpackev_w) +-TRANS(vpackev_d, LSX, gen_vvv, gen_helper_vpackev_d) +-TRANS(vpackod_b, LSX, gen_vvv, gen_helper_vpackod_b) +-TRANS(vpackod_h, LSX, gen_vvv, gen_helper_vpackod_h) +-TRANS(vpackod_w, LSX, gen_vvv, gen_helper_vpackod_w) +-TRANS(vpackod_d, LSX, gen_vvv, gen_helper_vpackod_d) +-TRANS(xvpackev_b, LASX, gen_xxx, gen_helper_vpackev_b) +-TRANS(xvpackev_h, LASX, gen_xxx, gen_helper_vpackev_h) +-TRANS(xvpackev_w, LASX, gen_xxx, gen_helper_vpackev_w) +-TRANS(xvpackev_d, LASX, gen_xxx, gen_helper_vpackev_d) +-TRANS(xvpackod_b, LASX, gen_xxx, gen_helper_vpackod_b) +-TRANS(xvpackod_h, LASX, gen_xxx, gen_helper_vpackod_h) +-TRANS(xvpackod_w, LASX, gen_xxx, gen_helper_vpackod_w) +-TRANS(xvpackod_d, LASX, gen_xxx, gen_helper_vpackod_d) +- +-TRANS(vpickev_b, LSX, gen_vvv, gen_helper_vpickev_b) +-TRANS(vpickev_h, LSX, gen_vvv, gen_helper_vpickev_h) +-TRANS(vpickev_w, LSX, gen_vvv, gen_helper_vpickev_w) +-TRANS(vpickev_d, LSX, gen_vvv, gen_helper_vpickev_d) +-TRANS(vpickod_b, LSX, gen_vvv, gen_helper_vpickod_b) +-TRANS(vpickod_h, LSX, gen_vvv, gen_helper_vpickod_h) +-TRANS(vpickod_w, LSX, gen_vvv, gen_helper_vpickod_w) +-TRANS(vpickod_d, LSX, gen_vvv, gen_helper_vpickod_d) +-TRANS(xvpickev_b, LASX, gen_xxx, gen_helper_vpickev_b) +-TRANS(xvpickev_h, LASX, gen_xxx, gen_helper_vpickev_h) +-TRANS(xvpickev_w, LASX, gen_xxx, gen_helper_vpickev_w) +-TRANS(xvpickev_d, LASX, gen_xxx, gen_helper_vpickev_d) +-TRANS(xvpickod_b, LASX, gen_xxx, gen_helper_vpickod_b) +-TRANS(xvpickod_h, LASX, gen_xxx, gen_helper_vpickod_h) +-TRANS(xvpickod_w, LASX, gen_xxx, gen_helper_vpickod_w) +-TRANS(xvpickod_d, LASX, gen_xxx, gen_helper_vpickod_d) +- +-TRANS(vilvl_b, LSX, gen_vvv, gen_helper_vilvl_b) +-TRANS(vilvl_h, LSX, gen_vvv, gen_helper_vilvl_h) +-TRANS(vilvl_w, LSX, gen_vvv, gen_helper_vilvl_w) +-TRANS(vilvl_d, LSX, gen_vvv, gen_helper_vilvl_d) +-TRANS(vilvh_b, LSX, gen_vvv, gen_helper_vilvh_b) +-TRANS(vilvh_h, LSX, gen_vvv, gen_helper_vilvh_h) +-TRANS(vilvh_w, LSX, gen_vvv, gen_helper_vilvh_w) +-TRANS(vilvh_d, LSX, gen_vvv, gen_helper_vilvh_d) +-TRANS(xvilvl_b, LASX, gen_xxx, gen_helper_vilvl_b) +-TRANS(xvilvl_h, LASX, gen_xxx, gen_helper_vilvl_h) +-TRANS(xvilvl_w, LASX, gen_xxx, gen_helper_vilvl_w) +-TRANS(xvilvl_d, LASX, gen_xxx, gen_helper_vilvl_d) +-TRANS(xvilvh_b, LASX, gen_xxx, gen_helper_vilvh_b) +-TRANS(xvilvh_h, LASX, gen_xxx, gen_helper_vilvh_h) +-TRANS(xvilvh_w, LASX, gen_xxx, gen_helper_vilvh_w) +-TRANS(xvilvh_d, LASX, gen_xxx, gen_helper_vilvh_d) +- +-TRANS(vshuf_b, LSX, gen_vvvv, gen_helper_vshuf_b) +-TRANS(vshuf_h, LSX, gen_vvv, gen_helper_vshuf_h) +-TRANS(vshuf_w, LSX, gen_vvv, gen_helper_vshuf_w) +-TRANS(vshuf_d, LSX, gen_vvv, gen_helper_vshuf_d) +-TRANS(xvshuf_b, LASX, gen_xxxx, gen_helper_vshuf_b) +-TRANS(xvshuf_h, LASX, gen_xxx, gen_helper_vshuf_h) +-TRANS(xvshuf_w, LASX, gen_xxx, gen_helper_vshuf_w) +-TRANS(xvshuf_d, LASX, gen_xxx, gen_helper_vshuf_d) +-TRANS(vshuf4i_b, LSX, gen_vv_i, gen_helper_vshuf4i_b) +-TRANS(vshuf4i_h, LSX, gen_vv_i, gen_helper_vshuf4i_h) +-TRANS(vshuf4i_w, LSX, gen_vv_i, gen_helper_vshuf4i_w) +-TRANS(vshuf4i_d, LSX, gen_vv_i, gen_helper_vshuf4i_d) +-TRANS(xvshuf4i_b, LASX, gen_xx_i, gen_helper_vshuf4i_b) +-TRANS(xvshuf4i_h, LASX, gen_xx_i, gen_helper_vshuf4i_h) +-TRANS(xvshuf4i_w, LASX, gen_xx_i, gen_helper_vshuf4i_w) +-TRANS(xvshuf4i_d, LASX, gen_xx_i, gen_helper_vshuf4i_d) +- +-TRANS(xvperm_w, LASX, gen_xxx, gen_helper_vperm_w) +-TRANS(vpermi_w, LSX, gen_vv_i, gen_helper_vpermi_w) +-TRANS(xvpermi_w, LASX, gen_xx_i, gen_helper_vpermi_w) +-TRANS(xvpermi_d, LASX, gen_xx_i, gen_helper_vpermi_d) +-TRANS(xvpermi_q, LASX, gen_xx_i, gen_helper_vpermi_q) +- +-TRANS(vextrins_b, LSX, gen_vv_i, gen_helper_vextrins_b) +-TRANS(vextrins_h, LSX, gen_vv_i, gen_helper_vextrins_h) +-TRANS(vextrins_w, LSX, gen_vv_i, gen_helper_vextrins_w) +-TRANS(vextrins_d, LSX, gen_vv_i, gen_helper_vextrins_d) +-TRANS(xvextrins_b, LASX, gen_xx_i, gen_helper_vextrins_b) +-TRANS(xvextrins_h, LASX, gen_xx_i, gen_helper_vextrins_h) +-TRANS(xvextrins_w, LASX, gen_xx_i, gen_helper_vextrins_w) +-TRANS(xvextrins_d, LASX, gen_xx_i, gen_helper_vextrins_d) +- +-static bool trans_vld(DisasContext *ctx, arg_vr_i *a) +-{ +- TCGv addr; +- TCGv_i64 rl, rh; +- TCGv_i128 val; +- +- if (!avail_LSX(ctx)) { +- return false; +- } +- +- if (!check_vec(ctx, 16)) { +- return true; +- } +- +- addr = gpr_src(ctx, a->rj, EXT_NONE); +- val = tcg_temp_new_i128(); +- rl = tcg_temp_new_i64(); +- rh = tcg_temp_new_i64(); +- +- addr = make_address_i(ctx, addr, a->imm); +- +- tcg_gen_qemu_ld_i128(val, addr, ctx->mem_idx, MO_128 | MO_TE); +- tcg_gen_extr_i128_i64(rl, rh, val); +- set_vreg64(rh, a->vd, 1); +- set_vreg64(rl, a->vd, 0); +- +- return true; +-} +- +-static bool trans_vst(DisasContext *ctx, arg_vr_i *a) +-{ +- TCGv addr; +- TCGv_i128 val; +- TCGv_i64 ah, al; +- +- if (!avail_LSX(ctx)) { +- return false; +- } +- +- if (!check_vec(ctx, 16)) { +- return true; +- } +- +- addr = gpr_src(ctx, a->rj, EXT_NONE); +- val = tcg_temp_new_i128(); +- ah = tcg_temp_new_i64(); +- al = tcg_temp_new_i64(); +- +- addr = make_address_i(ctx, addr, a->imm); +- +- get_vreg64(ah, a->vd, 1); +- get_vreg64(al, a->vd, 0); +- tcg_gen_concat_i64_i128(val, al, ah); +- tcg_gen_qemu_st_i128(val, addr, ctx->mem_idx, MO_128 | MO_TE); +- +- return true; +-} +- +-static bool trans_vldx(DisasContext *ctx, arg_vrr *a) +-{ +- TCGv addr, src1, src2; +- TCGv_i64 rl, rh; +- TCGv_i128 val; +- +- if (!avail_LSX(ctx)) { +- return false; +- } +- +- if (!check_vec(ctx, 16)) { +- return true; +- } +- +- src1 = gpr_src(ctx, a->rj, EXT_NONE); +- src2 = gpr_src(ctx, a->rk, EXT_NONE); +- val = tcg_temp_new_i128(); +- rl = tcg_temp_new_i64(); +- rh = tcg_temp_new_i64(); +- +- addr = make_address_x(ctx, src1, src2); +- tcg_gen_qemu_ld_i128(val, addr, ctx->mem_idx, MO_128 | MO_TE); +- tcg_gen_extr_i128_i64(rl, rh, val); +- set_vreg64(rh, a->vd, 1); +- set_vreg64(rl, a->vd, 0); +- +- return true; +-} +- +-static bool trans_vstx(DisasContext *ctx, arg_vrr *a) +-{ +- TCGv addr, src1, src2; +- TCGv_i64 ah, al; +- TCGv_i128 val; +- +- if (!avail_LSX(ctx)) { +- return false; +- } +- +- if (!check_vec(ctx, 16)) { +- return true; +- } +- +- src1 = gpr_src(ctx, a->rj, EXT_NONE); +- src2 = gpr_src(ctx, a->rk, EXT_NONE); +- val = tcg_temp_new_i128(); +- ah = tcg_temp_new_i64(); +- al = tcg_temp_new_i64(); +- +- addr = make_address_x(ctx, src1, src2); +- get_vreg64(ah, a->vd, 1); +- get_vreg64(al, a->vd, 0); +- tcg_gen_concat_i64_i128(val, al, ah); +- tcg_gen_qemu_st_i128(val, addr, ctx->mem_idx, MO_128 | MO_TE); +- +- return true; +-} +- +-static bool do_vldrepl_vl(DisasContext *ctx, arg_vr_i *a, +- uint32_t oprsz, MemOp mop) +-{ +- TCGv addr; +- TCGv_i64 val; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- addr = gpr_src(ctx, a->rj, EXT_NONE); +- val = tcg_temp_new_i64(); +- +- addr = make_address_i(ctx, addr, a->imm); +- +- tcg_gen_qemu_ld_i64(val, addr, ctx->mem_idx, mop); +- tcg_gen_gvec_dup_i64(mop, vec_full_offset(a->vd), oprsz, ctx->vl / 8, val); +- +- return true; +-} +- +-static bool do_vldrepl(DisasContext *ctx, arg_vr_i *a, MemOp mop) +-{ +- return do_vldrepl_vl(ctx, a, 16, mop); +-} +- +-static bool do_xvldrepl(DisasContext *ctx, arg_vr_i *a, MemOp mop) +-{ +- return do_vldrepl_vl(ctx, a, 32, mop); +-} +- +-TRANS(vldrepl_b, LSX, do_vldrepl, MO_8) +-TRANS(vldrepl_h, LSX, do_vldrepl, MO_16) +-TRANS(vldrepl_w, LSX, do_vldrepl, MO_32) +-TRANS(vldrepl_d, LSX, do_vldrepl, MO_64) +-TRANS(xvldrepl_b, LASX, do_xvldrepl, MO_8) +-TRANS(xvldrepl_h, LASX, do_xvldrepl, MO_16) +-TRANS(xvldrepl_w, LASX, do_xvldrepl, MO_32) +-TRANS(xvldrepl_d, LASX, do_xvldrepl, MO_64) +- +-static bool do_vstelm_vl(DisasContext *ctx, +- arg_vr_ii *a, uint32_t oprsz, MemOp mop) +-{ +- TCGv addr; +- TCGv_i64 val; +- +- if (!check_vec(ctx, oprsz)) { +- return true; +- } +- +- addr = gpr_src(ctx, a->rj, EXT_NONE); +- val = tcg_temp_new_i64(); +- +- addr = make_address_i(ctx, addr, a->imm); +- tcg_gen_ld_i64(val, tcg_env, vec_reg_offset(a->vd, a->imm2, mop)); +- tcg_gen_qemu_st_i64(val, addr, ctx->mem_idx, mop); +- return true; +-} +- +-static bool do_vstelm(DisasContext *ctx, arg_vr_ii *a, MemOp mop) +-{ +- return do_vstelm_vl(ctx, a, 16, mop); +-} +- +-static bool do_xvstelm(DisasContext *ctx, arg_vr_ii *a, MemOp mop) +-{ +- return do_vstelm_vl(ctx, a, 32, mop); +-} +- +-TRANS(vstelm_b, LSX, do_vstelm, MO_8) +-TRANS(vstelm_h, LSX, do_vstelm, MO_16) +-TRANS(vstelm_w, LSX, do_vstelm, MO_32) +-TRANS(vstelm_d, LSX, do_vstelm, MO_64) +-TRANS(xvstelm_b, LASX, do_xvstelm, MO_8) +-TRANS(xvstelm_h, LASX, do_xvstelm, MO_16) +-TRANS(xvstelm_w, LASX, do_xvstelm, MO_32) +-TRANS(xvstelm_d, LASX, do_xvstelm, MO_64) +- +-static bool gen_lasx_memory(DisasContext *ctx, arg_vr_i *a, +- void (*func)(DisasContext *, int, TCGv)) +-{ +- TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv temp = NULL; +- +- if (!check_vec(ctx, 32)) { +- return true; +- } +- +- if (a->imm) { +- temp = tcg_temp_new(); +- tcg_gen_addi_tl(temp, addr, a->imm); +- addr = temp; +- } +- +- func(ctx, a->vd, addr); +- return true; +-} +- +-static void gen_xvld(DisasContext *ctx, int vreg, TCGv addr) +-{ +- int i; +- TCGv temp = tcg_temp_new(); +- TCGv dest = tcg_temp_new(); +- +- tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUQ); +- set_vreg64(dest, vreg, 0); +- +- for (i = 1; i < 4; i++) { +- tcg_gen_addi_tl(temp, addr, 8 * i); +- tcg_gen_qemu_ld_i64(dest, temp, ctx->mem_idx, MO_TEUQ); +- set_vreg64(dest, vreg, i); +- } +-} +- +-static void gen_xvst(DisasContext * ctx, int vreg, TCGv addr) +-{ +- int i; +- TCGv temp = tcg_temp_new(); +- TCGv dest = tcg_temp_new(); +- +- get_vreg64(dest, vreg, 0); +- tcg_gen_qemu_st_i64(dest, addr, ctx->mem_idx, MO_TEUQ); +- +- for (i = 1; i < 4; i++) { +- tcg_gen_addi_tl(temp, addr, 8 * i); +- get_vreg64(dest, vreg, i); +- tcg_gen_qemu_st_i64(dest, temp, ctx->mem_idx, MO_TEUQ); +- } +-} +- +-TRANS(xvld, LASX, gen_lasx_memory, gen_xvld) +-TRANS(xvst, LASX, gen_lasx_memory, gen_xvst) +- +-static bool gen_lasx_memoryx(DisasContext *ctx, arg_vrr *a, +- void (*func)(DisasContext*, int, TCGv)) +-{ +- TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); +- TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); +- TCGv addr = tcg_temp_new(); +- +- if (!check_vec(ctx, 32)) { +- return true; +- } +- +- tcg_gen_add_tl(addr, src1, src2); +- func(ctx, a->vd, addr); +- +- return true; +-} +- +-TRANS(xvldx, LASX, gen_lasx_memoryx, gen_xvld) +-TRANS(xvstx, LASX, gen_lasx_memoryx, gen_xvst) +diff --git a/target/loongarch/iocsr_helper.c b/target/loongarch/iocsr_helper.c +deleted file mode 100644 +index 6cd01d5..0000000 +--- a/target/loongarch/iocsr_helper.c ++++ /dev/null +@@ -1,68 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- * +- * Helpers for IOCSR reads/writes +- */ +- +-#include "qemu/osdep.h" +-#include "cpu.h" +-#include "qemu/host-utils.h" +-#include "exec/helper-proto.h" +-#include "exec/exec-all.h" +-#include "exec/cpu_ldst.h" +- +-#define GET_MEMTXATTRS(cas) \ +- ((MemTxAttrs){.requester_id = env_cpu(cas)->cpu_index}) +- +-uint64_t helper_iocsrrd_b(CPULoongArchState *env, target_ulong r_addr) +-{ +- return address_space_ldub(&env->address_space_iocsr, r_addr, +- GET_MEMTXATTRS(env), NULL); +-} +- +-uint64_t helper_iocsrrd_h(CPULoongArchState *env, target_ulong r_addr) +-{ +- return address_space_lduw(&env->address_space_iocsr, r_addr, +- GET_MEMTXATTRS(env), NULL); +-} +- +-uint64_t helper_iocsrrd_w(CPULoongArchState *env, target_ulong r_addr) +-{ +- return address_space_ldl(&env->address_space_iocsr, r_addr, +- GET_MEMTXATTRS(env), NULL); +-} +- +-uint64_t helper_iocsrrd_d(CPULoongArchState *env, target_ulong r_addr) +-{ +- return address_space_ldq(&env->address_space_iocsr, r_addr, +- GET_MEMTXATTRS(env), NULL); +-} +- +-void helper_iocsrwr_b(CPULoongArchState *env, target_ulong w_addr, +- target_ulong val) +-{ +- address_space_stb(&env->address_space_iocsr, w_addr, +- val, GET_MEMTXATTRS(env), NULL); +-} +- +-void helper_iocsrwr_h(CPULoongArchState *env, target_ulong w_addr, +- target_ulong val) +-{ +- address_space_stw(&env->address_space_iocsr, w_addr, +- val, GET_MEMTXATTRS(env), NULL); +-} +- +-void helper_iocsrwr_w(CPULoongArchState *env, target_ulong w_addr, +- target_ulong val) +-{ +- address_space_stl(&env->address_space_iocsr, w_addr, +- val, GET_MEMTXATTRS(env), NULL); +-} +- +-void helper_iocsrwr_d(CPULoongArchState *env, target_ulong w_addr, +- target_ulong val) +-{ +- address_space_stq(&env->address_space_iocsr, w_addr, +- val, GET_MEMTXATTRS(env), NULL); +-} +diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build +index b3a0fb1..e84e4c5 100644 +--- a/target/loongarch/meson.build ++++ b/target/loongarch/meson.build +@@ -5,29 +5,16 @@ loongarch_ss.add(files( + 'cpu.c', + 'gdbstub.c', + )) +-loongarch_tcg_ss = ss.source_set() +-loongarch_tcg_ss.add(gen) +-loongarch_tcg_ss.add(files( +- 'fpu_helper.c', +- 'op_helper.c', +- 'translate.c', +- 'vec_helper.c', +-)) +-loongarch_tcg_ss.add(zlib) + + loongarch_system_ss = ss.source_set() + loongarch_system_ss.add(files( + 'loongarch-qmp-cmds.c', + 'machine.c', +- 'tlb_helper.c', +- 'constant_timer.c', +- 'csr_helper.c', +- 'iocsr_helper.c', + )) + + common_ss.add(when: 'CONFIG_LOONGARCH_DIS', if_true: [files('disas.c'), gen]) + +-loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) ++subdir('tcg') + + target_arch += {'loongarch': loongarch_ss} + target_system_arch += {'loongarch': loongarch_system_ss} +diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c +deleted file mode 100644 +index fe79c62..0000000 +--- a/target/loongarch/op_helper.c ++++ /dev/null +@@ -1,140 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * LoongArch emulation helpers for QEMU. +- * +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-#include "qemu/osdep.h" +-#include "qemu/log.h" +-#include "cpu.h" +-#include "qemu/host-utils.h" +-#include "exec/helper-proto.h" +-#include "exec/exec-all.h" +-#include "exec/cpu_ldst.h" +-#include "internals.h" +-#include "qemu/crc32c.h" +-#include +-#include "cpu-csr.h" +- +-/* Exceptions helpers */ +-void helper_raise_exception(CPULoongArchState *env, uint32_t exception) +-{ +- do_raise_exception(env, exception, GETPC()); +-} +- +-target_ulong helper_bitrev_w(target_ulong rj) +-{ +- return (int32_t)revbit32(rj); +-} +- +-target_ulong helper_bitrev_d(target_ulong rj) +-{ +- return revbit64(rj); +-} +- +-target_ulong helper_bitswap(target_ulong v) +-{ +- v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | +- ((v & (target_ulong)0x5555555555555555ULL) << 1); +- v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | +- ((v & (target_ulong)0x3333333333333333ULL) << 2); +- v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | +- ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); +- return v; +-} +- +-/* loongarch assert op */ +-void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) +-{ +- if (rj > rk) { +- env->CSR_BADV = rj; +- do_raise_exception(env, EXCCODE_BCE, GETPC()); +- } +-} +- +-void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) +-{ +- if (rj <= rk) { +- env->CSR_BADV = rj; +- do_raise_exception(env, EXCCODE_BCE, GETPC()); +- } +-} +- +-target_ulong helper_crc32(target_ulong val, target_ulong m, uint64_t sz) +-{ +- uint8_t buf[8]; +- target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); +- +- m &= mask; +- stq_le_p(buf, m); +- return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); +-} +- +-target_ulong helper_crc32c(target_ulong val, target_ulong m, uint64_t sz) +-{ +- uint8_t buf[8]; +- target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); +- m &= mask; +- stq_le_p(buf, m); +- return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff); +-} +- +-target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj) +-{ +- return rj >= ARRAY_SIZE(env->cpucfg) ? 0 : env->cpucfg[rj]; +-} +- +-uint64_t helper_rdtime_d(CPULoongArchState *env) +-{ +-#ifdef CONFIG_USER_ONLY +- return cpu_get_host_ticks(); +-#else +- uint64_t plv; +- LoongArchCPU *cpu = env_archcpu(env); +- +- plv = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV); +- if (extract64(env->CSR_MISC, R_CSR_MISC_DRDTL_SHIFT + plv, 1)) { +- do_raise_exception(env, EXCCODE_IPE, GETPC()); +- } +- +- return cpu_loongarch_get_constant_timer_counter(cpu); +-#endif +-} +- +-#ifndef CONFIG_USER_ONLY +-void helper_ertn(CPULoongArchState *env) +-{ +- uint64_t csr_pplv, csr_pie; +- if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { +- csr_pplv = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV); +- csr_pie = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE); +- +- env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); +- env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 0); +- env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 1); +- set_pc(env, env->CSR_TLBRERA); +- qemu_log_mask(CPU_LOG_INT, "%s: TLBRERA " TARGET_FMT_lx "\n", +- __func__, env->CSR_TLBRERA); +- } else { +- csr_pplv = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PPLV); +- csr_pie = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PIE); +- +- set_pc(env, env->CSR_ERA); +- qemu_log_mask(CPU_LOG_INT, "%s: ERA " TARGET_FMT_lx "\n", +- __func__, env->CSR_ERA); +- } +- env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, csr_pplv); +- env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, csr_pie); +- +- env->lladdr = 1; +-} +- +-void helper_idle(CPULoongArchState *env) +-{ +- CPUState *cs = env_cpu(env); +- +- cs->halted = 1; +- do_raise_exception(env, EXCP_HLT, 0); +-} +-#endif +diff --git a/target/loongarch/tcg/constant_timer.c b/target/loongarch/tcg/constant_timer.c +new file mode 100644 +index 0000000..1851f53 +--- /dev/null ++++ b/target/loongarch/tcg/constant_timer.c +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * QEMU LoongArch constant timer support ++ * ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/timer.h" ++#include "cpu.h" ++#include "internals.h" ++#include "cpu-csr.h" ++ ++#define TIMER_PERIOD 10 /* 10 ns period for 100 MHz frequency */ ++#define CONSTANT_TIMER_TICK_MASK 0xfffffffffffcUL ++#define CONSTANT_TIMER_ENABLE 0x1UL ++ ++uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu) ++{ ++ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD; ++} ++ ++uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu) ++{ ++ uint64_t now, expire; ++ ++ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ++ expire = timer_expire_time_ns(&cpu->timer); ++ ++ return (expire - now) / TIMER_PERIOD; ++} ++ ++void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, ++ uint64_t value) ++{ ++ CPULoongArchState *env = &cpu->env; ++ uint64_t now, next; ++ ++ env->CSR_TCFG = value; ++ if (value & CONSTANT_TIMER_ENABLE) { ++ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ++ next = now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; ++ timer_mod(&cpu->timer, next); ++ } else { ++ timer_del(&cpu->timer); ++ } ++} ++ ++void loongarch_constant_timer_cb(void *opaque) ++{ ++ LoongArchCPU *cpu = opaque; ++ CPULoongArchState *env = &cpu->env; ++ uint64_t now, next; ++ ++ if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) { ++ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ++ next = now + (env->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; ++ timer_mod(&cpu->timer, next); ++ } else { ++ env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0); ++ } ++ ++ loongarch_cpu_set_irq(opaque, IRQ_TIMER, 1); ++} +diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c +new file mode 100644 +index 0000000..5534155 +--- /dev/null ++++ b/target/loongarch/tcg/csr_helper.c +@@ -0,0 +1,97 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch emulation helpers for CSRs ++ * ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/main-loop.h" ++#include "cpu.h" ++#include "internals.h" ++#include "qemu/host-utils.h" ++#include "exec/helper-proto.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++#include "hw/irq.h" ++#include "cpu-csr.h" ++ ++target_ulong helper_csrrd_pgd(CPULoongArchState *env) ++{ ++ int64_t v; ++ ++ if (env->CSR_TLBRERA & 0x1) { ++ v = env->CSR_TLBRBADV; ++ } else { ++ v = env->CSR_BADV; ++ } ++ ++ if ((v >> 63) & 0x1) { ++ v = env->CSR_PGDH; ++ } else { ++ v = env->CSR_PGDL; ++ } ++ ++ return v; ++} ++ ++target_ulong helper_csrrd_cpuid(CPULoongArchState *env) ++{ ++ LoongArchCPU *lac = env_archcpu(env); ++ ++ env->CSR_CPUID = CPU(lac)->cpu_index; ++ ++ return env->CSR_CPUID; ++} ++ ++target_ulong helper_csrrd_tval(CPULoongArchState *env) ++{ ++ LoongArchCPU *cpu = env_archcpu(env); ++ ++ return cpu_loongarch_get_constant_timer_ticks(cpu); ++} ++ ++target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) ++{ ++ int64_t old_v = env->CSR_ESTAT; ++ ++ /* Only IS[1:0] can be written */ ++ env->CSR_ESTAT = deposit64(env->CSR_ESTAT, 0, 2, val); ++ ++ return old_v; ++} ++ ++target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val) ++{ ++ int64_t old_v = env->CSR_ASID; ++ ++ /* Only ASID filed of CSR_ASID can be written */ ++ env->CSR_ASID = deposit64(env->CSR_ASID, 0, 10, val); ++ if (old_v != env->CSR_ASID) { ++ tlb_flush(env_cpu(env)); ++ } ++ return old_v; ++} ++ ++target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val) ++{ ++ LoongArchCPU *cpu = env_archcpu(env); ++ int64_t old_v = env->CSR_TCFG; ++ ++ cpu_loongarch_store_constant_timer_config(cpu, val); ++ ++ return old_v; ++} ++ ++target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val) ++{ ++ LoongArchCPU *cpu = env_archcpu(env); ++ int64_t old_v = 0; ++ ++ if (val & 0x1) { ++ qemu_mutex_lock_iothread(); ++ loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0); ++ qemu_mutex_unlock_iothread(); ++ } ++ return old_v; ++} +diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c +new file mode 100644 +index 0000000..f6753c5 +--- /dev/null ++++ b/target/loongarch/tcg/fpu_helper.c +@@ -0,0 +1,879 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch float point emulation helpers for QEMU ++ * ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "exec/helper-proto.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++#include "fpu/softfloat.h" ++#include "internals.h" ++ ++static inline uint64_t nanbox_s(float32 fp) ++{ ++ return fp | MAKE_64BIT_MASK(32, 32); ++} ++ ++/* Convert loongarch rounding mode in fcsr0 to IEEE library */ ++static const FloatRoundMode ieee_rm[4] = { ++ float_round_nearest_even, ++ float_round_to_zero, ++ float_round_up, ++ float_round_down ++}; ++ ++void restore_fp_status(CPULoongArchState *env) ++{ ++ set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3], ++ &env->fp_status); ++ set_flush_to_zero(0, &env->fp_status); ++} ++ ++int ieee_ex_to_loongarch(int xcpt) ++{ ++ int ret = 0; ++ if (xcpt & float_flag_invalid) { ++ ret |= FP_INVALID; ++ } ++ if (xcpt & float_flag_overflow) { ++ ret |= FP_OVERFLOW; ++ } ++ if (xcpt & float_flag_underflow) { ++ ret |= FP_UNDERFLOW; ++ } ++ if (xcpt & float_flag_divbyzero) { ++ ret |= FP_DIV0; ++ } ++ if (xcpt & float_flag_inexact) { ++ ret |= FP_INEXACT; ++ } ++ return ret; ++} ++ ++static void update_fcsr0_mask(CPULoongArchState *env, uintptr_t pc, int mask) ++{ ++ int flags = get_float_exception_flags(&env->fp_status); ++ ++ set_float_exception_flags(0, &env->fp_status); ++ ++ flags &= ~mask; ++ ++ if (!flags) { ++ SET_FP_CAUSE(env->fcsr0, flags); ++ return; ++ } else { ++ flags = ieee_ex_to_loongarch(flags); ++ SET_FP_CAUSE(env->fcsr0, flags); ++ } ++ ++ if (GET_FP_ENABLES(env->fcsr0) & flags) { ++ do_raise_exception(env, EXCCODE_FPE, pc); ++ } else { ++ UPDATE_FP_FLAGS(env->fcsr0, flags); ++ } ++} ++ ++static void update_fcsr0(CPULoongArchState *env, uintptr_t pc) ++{ ++ update_fcsr0_mask(env, pc, 0); ++} ++ ++uint64_t helper_fadd_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_add((uint32_t)fj, (uint32_t)fk, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fadd_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = float64_add(fj, fk, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fsub_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_sub((uint32_t)fj, (uint32_t)fk, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fsub_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = float64_sub(fj, fk, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmul_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_mul((uint32_t)fj, (uint32_t)fk, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmul_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = float64_mul(fj, fk, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fdiv_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_div((uint32_t)fj, (uint32_t)fk, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fdiv_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = float64_div(fj, fk, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmax_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_maxnum((uint32_t)fj, (uint32_t)fk, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmax_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = float64_maxnum(fj, fk, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmin_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_minnum((uint32_t)fj, (uint32_t)fk, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmin_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = float64_minnum(fj, fk, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmaxa_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_maxnummag((uint32_t)fj, ++ (uint32_t)fk, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmaxa_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = float64_maxnummag(fj, fk, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmina_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_minnummag((uint32_t)fj, ++ (uint32_t)fk, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmina_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ ++ fd = float64_minnummag(fj, fk, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fscaleb_s(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ int32_t n = (int32_t)fk; ++ ++ fd = nanbox_s(float32_scalbn((uint32_t)fj, ++ n > 0x200 ? 0x200 : ++ n < -0x200 ? -0x200 : n, ++ &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fscaleb_d(CPULoongArchState *env, uint64_t fj, uint64_t fk) ++{ ++ uint64_t fd; ++ int64_t n = (int64_t)fk; ++ ++ fd = float64_scalbn(fj, ++ n > 0x1000 ? 0x1000 : ++ n < -0x1000 ? -0x1000 : n, ++ &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fsqrt_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_sqrt((uint32_t)fj, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fsqrt_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = float64_sqrt(fj, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_frecip_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_div(float32_one, (uint32_t)fj, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_frecip_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = float64_div(float64_one, fj, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_frsqrt_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ uint32_t fp; ++ ++ fp = float32_sqrt((uint32_t)fj, &env->fp_status); ++ fd = nanbox_s(float32_div(float32_one, fp, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_frsqrt_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fp, fd; ++ ++ fp = float64_sqrt(fj, &env->fp_status); ++ fd = float64_div(float64_one, fp, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_flogb_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ uint32_t fp; ++ float_status *status = &env->fp_status; ++ FloatRoundMode old_mode = get_float_rounding_mode(status); ++ ++ set_float_rounding_mode(float_round_down, status); ++ fp = float32_log2((uint32_t)fj, status); ++ fd = nanbox_s(float32_round_to_int(fp, status)); ++ set_float_rounding_mode(old_mode, status); ++ update_fcsr0_mask(env, GETPC(), float_flag_inexact); ++ return fd; ++} ++ ++uint64_t helper_flogb_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ float_status *status = &env->fp_status; ++ FloatRoundMode old_mode = get_float_rounding_mode(status); ++ ++ set_float_rounding_mode(float_round_down, status); ++ fd = float64_log2(fj, status); ++ fd = float64_round_to_int(fd, status); ++ set_float_rounding_mode(old_mode, status); ++ update_fcsr0_mask(env, GETPC(), float_flag_inexact); ++ return fd; ++} ++ ++uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj) ++{ ++ float32 f = fj; ++ bool sign = float32_is_neg(f); ++ ++ if (float32_is_infinity(f)) { ++ return sign ? 1 << 2 : 1 << 6; ++ } else if (float32_is_zero(f)) { ++ return sign ? 1 << 5 : 1 << 9; ++ } else if (float32_is_zero_or_denormal(f)) { ++ return sign ? 1 << 4 : 1 << 8; ++ } else if (float32_is_any_nan(f)) { ++ float_status s = { }; /* for snan_bit_is_one */ ++ return float32_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0; ++ } else { ++ return sign ? 1 << 3 : 1 << 7; ++ } ++} ++ ++uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj) ++{ ++ float64 f = fj; ++ bool sign = float64_is_neg(f); ++ ++ if (float64_is_infinity(f)) { ++ return sign ? 1 << 2 : 1 << 6; ++ } else if (float64_is_zero(f)) { ++ return sign ? 1 << 5 : 1 << 9; ++ } else if (float64_is_zero_or_denormal(f)) { ++ return sign ? 1 << 4 : 1 << 8; ++ } else if (float64_is_any_nan(f)) { ++ float_status s = { }; /* for snan_bit_is_one */ ++ return float64_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0; ++ } else { ++ return sign ? 1 << 3 : 1 << 7; ++ } ++} ++ ++uint64_t helper_fmuladd_s(CPULoongArchState *env, uint64_t fj, ++ uint64_t fk, uint64_t fa, uint32_t flag) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float32_muladd((uint32_t)fj, (uint32_t)fk, ++ (uint32_t)fa, flag, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fmuladd_d(CPULoongArchState *env, uint64_t fj, ++ uint64_t fk, uint64_t fa, uint32_t flag) ++{ ++ uint64_t fd; ++ ++ fd = float64_muladd(fj, fk, fa, flag, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++static uint64_t fcmp_common(CPULoongArchState *env, FloatRelation cmp, ++ uint32_t flags) ++{ ++ bool ret; ++ ++ switch (cmp) { ++ case float_relation_less: ++ ret = (flags & FCMP_LT); ++ break; ++ case float_relation_equal: ++ ret = (flags & FCMP_EQ); ++ break; ++ case float_relation_greater: ++ ret = (flags & FCMP_GT); ++ break; ++ case float_relation_unordered: ++ ret = (flags & FCMP_UN); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ update_fcsr0(env, GETPC()); ++ ++ return ret; ++} ++ ++/* fcmp_cXXX_s */ ++uint64_t helper_fcmp_c_s(CPULoongArchState *env, uint64_t fj, ++ uint64_t fk, uint32_t flags) ++{ ++ FloatRelation cmp = float32_compare_quiet((uint32_t)fj, ++ (uint32_t)fk, &env->fp_status); ++ return fcmp_common(env, cmp, flags); ++} ++ ++/* fcmp_sXXX_s */ ++uint64_t helper_fcmp_s_s(CPULoongArchState *env, uint64_t fj, ++ uint64_t fk, uint32_t flags) ++{ ++ FloatRelation cmp = float32_compare((uint32_t)fj, ++ (uint32_t)fk, &env->fp_status); ++ return fcmp_common(env, cmp, flags); ++} ++ ++/* fcmp_cXXX_d */ ++uint64_t helper_fcmp_c_d(CPULoongArchState *env, uint64_t fj, ++ uint64_t fk, uint32_t flags) ++{ ++ FloatRelation cmp = float64_compare_quiet(fj, fk, &env->fp_status); ++ return fcmp_common(env, cmp, flags); ++} ++ ++/* fcmp_sXXX_d */ ++uint64_t helper_fcmp_s_d(CPULoongArchState *env, uint64_t fj, ++ uint64_t fk, uint32_t flags) ++{ ++ FloatRelation cmp = float64_compare(fj, fk, &env->fp_status); ++ return fcmp_common(env, cmp, flags); ++} ++ ++/* floating point conversion */ ++uint64_t helper_fcvt_s_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(float64_to_float32(fj, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_fcvt_d_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = float32_to_float64((uint32_t)fj, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ffint_s_w(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(int32_to_float32((int32_t)fj, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ffint_s_l(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = nanbox_s(int64_to_float32(fj, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ffint_d_w(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = int32_to_float64((int32_t)fj, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ffint_d_l(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = int64_to_float64(fj, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_frint_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = (uint64_t)(float32_round_to_int((uint32_t)fj, &env->fp_status)); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_frint_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = float64_round_to_int(fj, &env->fp_status); ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrm_l_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_down, &env->fp_status); ++ fd = float64_to_int64(fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float64_is_any_nan(fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrm_l_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_down, &env->fp_status); ++ fd = float32_to_int64((uint32_t)fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float32_is_any_nan((uint32_t)fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrm_w_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_down, &env->fp_status); ++ fd = (uint64_t)float64_to_int32(fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float64_is_any_nan(fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrm_w_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_down, &env->fp_status); ++ fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float32_is_any_nan((uint32_t)fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrp_l_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_up, &env->fp_status); ++ fd = float64_to_int64(fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float64_is_any_nan(fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrp_l_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_up, &env->fp_status); ++ fd = float32_to_int64((uint32_t)fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float32_is_any_nan((uint32_t)fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrp_w_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_up, &env->fp_status); ++ fd = (uint64_t)float64_to_int32(fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float64_is_any_nan(fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrp_w_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_up, &env->fp_status); ++ fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float32_is_any_nan((uint32_t)fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrz_l_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ fd = float64_to_int64_round_to_zero(fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float64_is_any_nan(fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrz_l_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ fd = float32_to_int64_round_to_zero((uint32_t)fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float32_is_any_nan((uint32_t)fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrz_w_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ fd = (uint64_t)float64_to_int32_round_to_zero(fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float64_is_any_nan(fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrz_w_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint32_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ fd = float32_to_int32_round_to_zero((uint32_t)fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float32_is_any_nan((uint32_t)fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return (uint64_t)fd; ++} ++ ++uint64_t helper_ftintrne_l_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_nearest_even, &env->fp_status); ++ fd = float64_to_int64(fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float64_is_any_nan(fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrne_l_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_nearest_even, &env->fp_status); ++ fd = float32_to_int64((uint32_t)fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float32_is_any_nan((uint32_t)fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrne_w_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_nearest_even, &env->fp_status); ++ fd = (uint64_t)float64_to_int32(fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float64_is_any_nan(fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftintrne_w_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint32_t fd; ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); ++ ++ set_float_rounding_mode(float_round_nearest_even, &env->fp_status); ++ fd = float32_to_int32((uint32_t)fj, &env->fp_status); ++ set_float_rounding_mode(old_mode, &env->fp_status); ++ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float32_is_any_nan((uint32_t)fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return (uint64_t)fd; ++} ++ ++uint64_t helper_ftint_l_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = float64_to_int64(fj, &env->fp_status); ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float64_is_any_nan(fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftint_l_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = float32_to_int64((uint32_t)fj, &env->fp_status); ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float32_is_any_nan((uint32_t)fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftint_w_s(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = (uint64_t)float32_to_int32((uint32_t)fj, &env->fp_status); ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float32_is_any_nan((uint32_t)fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++uint64_t helper_ftint_w_d(CPULoongArchState *env, uint64_t fj) ++{ ++ uint64_t fd; ++ ++ fd = (uint64_t)float64_to_int32(fj, &env->fp_status); ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { ++ if (float64_is_any_nan(fj)) { ++ fd = 0; ++ } ++ } ++ update_fcsr0(env, GETPC()); ++ return fd; ++} ++ ++void helper_set_rounding_mode(CPULoongArchState *env) ++{ ++ set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3], ++ &env->fp_status); ++} +diff --git a/target/loongarch/tcg/insn_trans/trans_arith.c.inc b/target/loongarch/tcg/insn_trans/trans_arith.c.inc +new file mode 100644 +index 0000000..2be057e +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_arith.c.inc +@@ -0,0 +1,304 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++static bool gen_rrr(DisasContext *ctx, arg_rrr *a, ++ DisasExtend src1_ext, DisasExtend src2_ext, ++ DisasExtend dst_ext, void (*func)(TCGv, TCGv, TCGv)) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, dst_ext); ++ TCGv src1 = gpr_src(ctx, a->rj, src1_ext); ++ TCGv src2 = gpr_src(ctx, a->rk, src2_ext); ++ ++ func(dest, src1, src2); ++ gen_set_gpr(a->rd, dest, dst_ext); ++ ++ return true; ++} ++ ++static bool gen_rri_v(DisasContext *ctx, arg_rr_i *a, ++ DisasExtend src_ext, DisasExtend dst_ext, ++ void (*func)(TCGv, TCGv, TCGv)) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, dst_ext); ++ TCGv src1 = gpr_src(ctx, a->rj, src_ext); ++ TCGv src2 = tcg_constant_tl(a->imm); ++ ++ func(dest, src1, src2); ++ gen_set_gpr(a->rd, dest, dst_ext); ++ ++ return true; ++} ++ ++static bool gen_rri_c(DisasContext *ctx, arg_rr_i *a, ++ DisasExtend src_ext, DisasExtend dst_ext, ++ void (*func)(TCGv, TCGv, target_long)) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, dst_ext); ++ TCGv src1 = gpr_src(ctx, a->rj, src_ext); ++ ++ func(dest, src1, a->imm); ++ gen_set_gpr(a->rd, dest, dst_ext); ++ ++ return true; ++} ++ ++static bool gen_rrr_sa(DisasContext *ctx, arg_rrr_sa *a, ++ DisasExtend src_ext, DisasExtend dst_ext, ++ void (*func)(TCGv, TCGv, TCGv, target_long)) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, dst_ext); ++ TCGv src1 = gpr_src(ctx, a->rj, src_ext); ++ TCGv src2 = gpr_src(ctx, a->rk, src_ext); ++ ++ func(dest, src1, src2, a->sa); ++ gen_set_gpr(a->rd, dest, dst_ext); ++ ++ return true; ++} ++ ++static bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ ++ tcg_gen_movi_tl(dest, a->imm << 12); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static bool gen_pc(DisasContext *ctx, arg_r_i *a, ++ target_ulong (*func)(target_ulong, int)) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ target_ulong addr = make_address_pc(ctx, func(ctx->base.pc_next, a->imm)); ++ ++ tcg_gen_movi_tl(dest, addr); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static void gen_slt(TCGv dest, TCGv src1, TCGv src2) ++{ ++ tcg_gen_setcond_tl(TCG_COND_LT, dest, src1, src2); ++} ++ ++static void gen_sltu(TCGv dest, TCGv src1, TCGv src2) ++{ ++ tcg_gen_setcond_tl(TCG_COND_LTU, dest, src1, src2); ++} ++ ++static void gen_mulh_w(TCGv dest, TCGv src1, TCGv src2) ++{ ++ tcg_gen_mul_i64(dest, src1, src2); ++ tcg_gen_sari_i64(dest, dest, 32); ++} ++ ++static void gen_mulh_d(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv discard = tcg_temp_new(); ++ tcg_gen_muls2_tl(discard, dest, src1, src2); ++} ++ ++static void gen_mulh_du(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv discard = tcg_temp_new(); ++ tcg_gen_mulu2_tl(discard, dest, src1, src2); ++} ++ ++static void prep_divisor_d(TCGv ret, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ TCGv zero = tcg_constant_tl(0); ++ ++ /* ++ * If min / -1, set the divisor to 1. ++ * This avoids potential host overflow trap and produces min. ++ * If x / 0, set the divisor to 1. ++ * This avoids potential host overflow trap; ++ * the required result is undefined. ++ */ ++ tcg_gen_setcondi_tl(TCG_COND_EQ, ret, src1, INT64_MIN); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t0, src2, -1); ++ tcg_gen_setcondi_tl(TCG_COND_EQ, t1, src2, 0); ++ tcg_gen_and_tl(ret, ret, t0); ++ tcg_gen_or_tl(ret, ret, t1); ++ tcg_gen_movcond_tl(TCG_COND_NE, ret, ret, zero, ret, src2); ++} ++ ++static void prep_divisor_du(TCGv ret, TCGv src2) ++{ ++ TCGv zero = tcg_constant_tl(0); ++ TCGv one = tcg_constant_tl(1); ++ ++ /* ++ * If x / 0, set the divisor to 1. ++ * This avoids potential host overflow trap; ++ * the required result is undefined. ++ */ ++ tcg_gen_movcond_tl(TCG_COND_EQ, ret, src2, zero, one, src2); ++} ++ ++static void gen_div_d(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ prep_divisor_d(t0, src1, src2); ++ tcg_gen_div_tl(dest, src1, t0); ++} ++ ++static void gen_rem_d(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ prep_divisor_d(t0, src1, src2); ++ tcg_gen_rem_tl(dest, src1, t0); ++} ++ ++static void gen_div_du(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ prep_divisor_du(t0, src2); ++ tcg_gen_divu_tl(dest, src1, t0); ++} ++ ++static void gen_rem_du(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ prep_divisor_du(t0, src2); ++ tcg_gen_remu_tl(dest, src1, t0); ++} ++ ++static void gen_div_w(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ /* We need not check for integer overflow for div_w. */ ++ prep_divisor_du(t0, src2); ++ tcg_gen_div_tl(dest, src1, t0); ++} ++ ++static void gen_rem_w(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ /* We need not check for integer overflow for rem_w. */ ++ prep_divisor_du(t0, src2); ++ tcg_gen_rem_tl(dest, src1, t0); ++} ++ ++static void gen_alsl(TCGv dest, TCGv src1, TCGv src2, target_long sa) ++{ ++ TCGv t0 = tcg_temp_new(); ++ tcg_gen_shli_tl(t0, src1, sa); ++ tcg_gen_add_tl(dest, t0, src2); ++} ++ ++static bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE); ++ TCGv src2 = tcg_constant_tl(a->imm); ++ ++ if (!avail_64(ctx)) { ++ return false; ++ } ++ ++ tcg_gen_deposit_tl(dest, src1, src2, 32, 32); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = tcg_constant_tl(a->imm); ++ ++ if (!avail_64(ctx)) { ++ return false; ++ } ++ ++ tcg_gen_deposit_tl(dest, src1, src2, 52, 12); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static target_ulong gen_pcaddi(target_ulong pc, int imm) ++{ ++ return pc + (imm << 2); ++} ++ ++static target_ulong gen_pcalau12i(target_ulong pc, int imm) ++{ ++ return (pc + (imm << 12)) & ~0xfff; ++} ++ ++static target_ulong gen_pcaddu12i(target_ulong pc, int imm) ++{ ++ return pc + (imm << 12); ++} ++ ++static target_ulong gen_pcaddu18i(target_ulong pc, int imm) ++{ ++ return pc + ((target_ulong)(imm) << 18); ++} ++ ++static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ if (!avail_64(ctx)) { ++ return false; ++ } ++ ++ tcg_gen_addi_tl(dest, src1, a->imm << 16); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++TRANS(add_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl) ++TRANS(add_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl) ++TRANS(sub_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_sub_tl) ++TRANS(sub_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl) ++TRANS(and, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_and_tl) ++TRANS(or, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_or_tl) ++TRANS(xor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_xor_tl) ++TRANS(nor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_nor_tl) ++TRANS(andn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_andc_tl) ++TRANS(orn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_orc_tl) ++TRANS(slt, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_slt) ++TRANS(sltu, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sltu) ++TRANS(mul_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, tcg_gen_mul_tl) ++TRANS(mul_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl) ++TRANS(mulh_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, gen_mulh_w) ++TRANS(mulh_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, gen_mulh_w) ++TRANS(mulh_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_d) ++TRANS(mulh_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_du) ++TRANS(mulw_d_w, 64, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, tcg_gen_mul_tl) ++TRANS(mulw_d_wu, 64, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, tcg_gen_mul_tl) ++TRANS(div_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_div_w) ++TRANS(mod_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_rem_w) ++TRANS(div_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_div_du) ++TRANS(mod_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_rem_du) ++TRANS(div_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_d) ++TRANS(mod_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_d) ++TRANS(div_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_du) ++TRANS(mod_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_du) ++TRANS(slti, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_slt) ++TRANS(sltui, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_sltu) ++TRANS(addi_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_addi_tl) ++TRANS(addi_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_addi_tl) ++TRANS(alsl_w, ALL, gen_rrr_sa, EXT_NONE, EXT_SIGN, gen_alsl) ++TRANS(alsl_wu, 64, gen_rrr_sa, EXT_NONE, EXT_ZERO, gen_alsl) ++TRANS(alsl_d, 64, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_alsl) ++TRANS(pcaddi, ALL, gen_pc, gen_pcaddi) ++TRANS(pcalau12i, ALL, gen_pc, gen_pcalau12i) ++TRANS(pcaddu12i, ALL, gen_pc, gen_pcaddu12i) ++TRANS(pcaddu18i, 64, gen_pc, gen_pcaddu18i) ++TRANS(andi, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_andi_tl) ++TRANS(ori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_ori_tl) ++TRANS(xori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_xori_tl) +diff --git a/target/loongarch/tcg/insn_trans/trans_atomic.c.inc b/target/loongarch/tcg/insn_trans/trans_atomic.c.inc +new file mode 100644 +index 0000000..80c2e28 +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_atomic.c.inc +@@ -0,0 +1,111 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++static bool gen_ll(DisasContext *ctx, arg_rr_i *a, MemOp mop) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv t0 = make_address_i(ctx, src1, a->imm); ++ ++ tcg_gen_qemu_ld_i64(dest, t0, ctx->mem_idx, mop); ++ tcg_gen_st_tl(t0, tcg_env, offsetof(CPULoongArchState, lladdr)); ++ tcg_gen_st_tl(dest, tcg_env, offsetof(CPULoongArchState, llval)); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static bool gen_sc(DisasContext *ctx, arg_rr_i *a, MemOp mop) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rd, EXT_NONE); ++ TCGv t0 = tcg_temp_new(); ++ TCGv val = tcg_temp_new(); ++ ++ TCGLabel *l1 = gen_new_label(); ++ TCGLabel *done = gen_new_label(); ++ ++ tcg_gen_addi_tl(t0, src1, a->imm); ++ tcg_gen_brcond_tl(TCG_COND_EQ, t0, cpu_lladdr, l1); ++ tcg_gen_movi_tl(dest, 0); ++ tcg_gen_br(done); ++ ++ gen_set_label(l1); ++ tcg_gen_mov_tl(val, src2); ++ /* generate cmpxchg */ ++ tcg_gen_atomic_cmpxchg_tl(t0, cpu_lladdr, cpu_llval, ++ val, ctx->mem_idx, mop); ++ tcg_gen_setcond_tl(TCG_COND_EQ, dest, t0, cpu_llval); ++ gen_set_label(done); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static bool gen_am(DisasContext *ctx, arg_rrr *a, ++ void (*func)(TCGv, TCGv, TCGv, TCGArg, MemOp), ++ MemOp mop) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv val = gpr_src(ctx, a->rk, EXT_NONE); ++ ++ if (a->rd != 0 && (a->rj == a->rd || a->rk == a->rd)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Warning: source register overlaps destination register" ++ "in atomic insn at pc=0x" TARGET_FMT_lx "\n", ++ ctx->base.pc_next - 4); ++ return false; ++ } ++ ++ addr = make_address_i(ctx, addr, 0); ++ ++ func(dest, addr, val, ctx->mem_idx, mop); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++TRANS(ll_w, ALL, gen_ll, MO_TESL) ++TRANS(sc_w, ALL, gen_sc, MO_TESL) ++TRANS(ll_d, 64, gen_ll, MO_TEUQ) ++TRANS(sc_d, 64, gen_sc, MO_TEUQ) ++TRANS(amswap_w, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) ++TRANS(amswap_d, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) ++TRANS(amadd_w, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) ++TRANS(amadd_d, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) ++TRANS(amand_w, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) ++TRANS(amand_d, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) ++TRANS(amor_w, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) ++TRANS(amor_d, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) ++TRANS(amxor_w, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) ++TRANS(amxor_d, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) ++TRANS(ammax_w, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) ++TRANS(ammax_d, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) ++TRANS(ammin_w, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) ++TRANS(ammin_d, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) ++TRANS(ammax_wu, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) ++TRANS(ammax_du, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) ++TRANS(ammin_wu, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) ++TRANS(ammin_du, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) ++TRANS(amswap_db_w, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) ++TRANS(amswap_db_d, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) ++TRANS(amadd_db_w, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) ++TRANS(amadd_db_d, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) ++TRANS(amand_db_w, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) ++TRANS(amand_db_d, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) ++TRANS(amor_db_w, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) ++TRANS(amor_db_d, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) ++TRANS(amxor_db_w, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) ++TRANS(amxor_db_d, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) ++TRANS(ammax_db_w, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) ++TRANS(ammax_db_d, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) ++TRANS(ammin_db_w, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) ++TRANS(ammin_db_d, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) ++TRANS(ammax_db_wu, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) ++TRANS(ammax_db_du, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) ++TRANS(ammin_db_wu, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) ++TRANS(ammin_db_du, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +diff --git a/target/loongarch/tcg/insn_trans/trans_bit.c.inc b/target/loongarch/tcg/insn_trans/trans_bit.c.inc +new file mode 100644 +index 0000000..ee5fa00 +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_bit.c.inc +@@ -0,0 +1,208 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++static bool gen_rr(DisasContext *ctx, arg_rr *a, ++ DisasExtend src_ext, DisasExtend dst_ext, ++ void (*func)(TCGv, TCGv)) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, dst_ext); ++ TCGv src1 = gpr_src(ctx, a->rj, src_ext); ++ ++ func(dest, src1); ++ gen_set_gpr(a->rd, dest, dst_ext); ++ ++ return true; ++} ++ ++static void gen_bytepick_w(TCGv dest, TCGv src1, TCGv src2, target_long sa) ++{ ++ tcg_gen_concat_tl_i64(dest, src1, src2); ++ tcg_gen_sextract_i64(dest, dest, (32 - sa * 8), 32); ++} ++ ++static void gen_bytepick_d(TCGv dest, TCGv src1, TCGv src2, target_long sa) ++{ ++ tcg_gen_extract2_i64(dest, src1, src2, (64 - sa * 8)); ++} ++ ++static bool gen_bstrins(DisasContext *ctx, arg_rr_ms_ls *a, ++ DisasExtend dst_ext) ++{ ++ TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ ++ if (a->ls > a->ms) { ++ return false; ++ } ++ ++ tcg_gen_deposit_tl(dest, src1, src2, a->ls, a->ms - a->ls + 1); ++ gen_set_gpr(a->rd, dest, dst_ext); ++ return true; ++} ++ ++static bool gen_bstrpick(DisasContext *ctx, arg_rr_ms_ls *a, ++ DisasExtend dst_ext) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ if (a->ls > a->ms) { ++ return false; ++ } ++ ++ tcg_gen_extract_tl(dest, src1, a->ls, a->ms - a->ls + 1); ++ gen_set_gpr(a->rd, dest, dst_ext); ++ return true; ++} ++ ++static void gen_clz_w(TCGv dest, TCGv src1) ++{ ++ tcg_gen_clzi_tl(dest, src1, TARGET_LONG_BITS); ++ tcg_gen_subi_tl(dest, dest, TARGET_LONG_BITS - 32); ++} ++ ++static void gen_clo_w(TCGv dest, TCGv src1) ++{ ++ tcg_gen_not_tl(dest, src1); ++ tcg_gen_ext32u_tl(dest, dest); ++ gen_clz_w(dest, dest); ++} ++ ++static void gen_ctz_w(TCGv dest, TCGv src1) ++{ ++ tcg_gen_ori_tl(dest, src1, (target_ulong)MAKE_64BIT_MASK(32, 32)); ++ tcg_gen_ctzi_tl(dest, dest, TARGET_LONG_BITS); ++} ++ ++static void gen_cto_w(TCGv dest, TCGv src1) ++{ ++ tcg_gen_not_tl(dest, src1); ++ gen_ctz_w(dest, dest); ++} ++ ++static void gen_clz_d(TCGv dest, TCGv src1) ++{ ++ tcg_gen_clzi_i64(dest, src1, TARGET_LONG_BITS); ++} ++ ++static void gen_clo_d(TCGv dest, TCGv src1) ++{ ++ tcg_gen_not_tl(dest, src1); ++ gen_clz_d(dest, dest); ++} ++ ++static void gen_ctz_d(TCGv dest, TCGv src1) ++{ ++ tcg_gen_ctzi_tl(dest, src1, TARGET_LONG_BITS); ++} ++ ++static void gen_cto_d(TCGv dest, TCGv src1) ++{ ++ tcg_gen_not_tl(dest, src1); ++ gen_ctz_d(dest, dest); ++} ++ ++static void gen_revb_2w(TCGv dest, TCGv src1) ++{ ++ tcg_gen_bswap64_i64(dest, src1); ++ tcg_gen_rotri_i64(dest, dest, 32); ++} ++ ++static void gen_revb_2h(TCGv dest, TCGv src1) ++{ ++ TCGv mask = tcg_constant_tl(0x00FF00FF); ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ ++ tcg_gen_shri_tl(t0, src1, 8); ++ tcg_gen_and_tl(t0, t0, mask); ++ tcg_gen_and_tl(t1, src1, mask); ++ tcg_gen_shli_tl(t1, t1, 8); ++ tcg_gen_or_tl(dest, t0, t1); ++} ++ ++static void gen_revb_4h(TCGv dest, TCGv src1) ++{ ++ TCGv mask = tcg_constant_tl(0x00FF00FF00FF00FFULL); ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ ++ tcg_gen_shri_tl(t0, src1, 8); ++ tcg_gen_and_tl(t0, t0, mask); ++ tcg_gen_and_tl(t1, src1, mask); ++ tcg_gen_shli_tl(t1, t1, 8); ++ tcg_gen_or_tl(dest, t0, t1); ++} ++ ++static void gen_revh_2w(TCGv dest, TCGv src1) ++{ ++ TCGv_i64 t0 = tcg_temp_new_i64(); ++ TCGv_i64 t1 = tcg_temp_new_i64(); ++ TCGv_i64 mask = tcg_constant_i64(0x0000ffff0000ffffull); ++ ++ tcg_gen_shri_i64(t0, src1, 16); ++ tcg_gen_and_i64(t1, src1, mask); ++ tcg_gen_and_i64(t0, t0, mask); ++ tcg_gen_shli_i64(t1, t1, 16); ++ tcg_gen_or_i64(dest, t1, t0); ++} ++ ++static void gen_revh_d(TCGv dest, TCGv src1) ++{ ++ TCGv t0 = tcg_temp_new(); ++ TCGv t1 = tcg_temp_new(); ++ TCGv mask = tcg_constant_tl(0x0000FFFF0000FFFFULL); ++ ++ tcg_gen_shri_tl(t1, src1, 16); ++ tcg_gen_and_tl(t1, t1, mask); ++ tcg_gen_and_tl(t0, src1, mask); ++ tcg_gen_shli_tl(t0, t0, 16); ++ tcg_gen_or_tl(t0, t0, t1); ++ tcg_gen_rotri_tl(dest, t0, 32); ++} ++ ++static void gen_maskeqz(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv zero = tcg_constant_tl(0); ++ ++ tcg_gen_movcond_tl(TCG_COND_EQ, dest, src2, zero, zero, src1); ++} ++ ++static void gen_masknez(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv zero = tcg_constant_tl(0); ++ ++ tcg_gen_movcond_tl(TCG_COND_NE, dest, src2, zero, zero, src1); ++} ++ ++TRANS(ext_w_h, ALL, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext16s_tl) ++TRANS(ext_w_b, ALL, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext8s_tl) ++TRANS(clo_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_clo_w) ++TRANS(clz_w, ALL, gen_rr, EXT_ZERO, EXT_NONE, gen_clz_w) ++TRANS(cto_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_cto_w) ++TRANS(ctz_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_w) ++TRANS(clo_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_clo_d) ++TRANS(clz_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_clz_d) ++TRANS(cto_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_cto_d) ++TRANS(ctz_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_d) ++TRANS(revb_2h, ALL, gen_rr, EXT_NONE, EXT_SIGN, gen_revb_2h) ++TRANS(revb_4h, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revb_4h) ++TRANS(revb_2w, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revb_2w) ++TRANS(revb_d, 64, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_bswap64_i64) ++TRANS(revh_2w, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revh_2w) ++TRANS(revh_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revh_d) ++TRANS(bitrev_4b, ALL, gen_rr, EXT_ZERO, EXT_SIGN, gen_helper_bitswap) ++TRANS(bitrev_8b, 64, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitswap) ++TRANS(bitrev_w, ALL, gen_rr, EXT_NONE, EXT_SIGN, gen_helper_bitrev_w) ++TRANS(bitrev_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitrev_d) ++TRANS(maskeqz, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_maskeqz) ++TRANS(masknez, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez) ++TRANS(bytepick_w, ALL, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_w) ++TRANS(bytepick_d, 64, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_d) ++TRANS(bstrins_w, ALL, gen_bstrins, EXT_SIGN) ++TRANS(bstrins_d, 64, gen_bstrins, EXT_NONE) ++TRANS(bstrpick_w, ALL, gen_bstrpick, EXT_SIGN) ++TRANS(bstrpick_d, 64, gen_bstrpick, EXT_NONE) +diff --git a/target/loongarch/tcg/insn_trans/trans_branch.c.inc b/target/loongarch/tcg/insn_trans/trans_branch.c.inc +new file mode 100644 +index 0000000..221e515 +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_branch.c.inc +@@ -0,0 +1,84 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++static bool trans_b(DisasContext *ctx, arg_b *a) ++{ ++ gen_goto_tb(ctx, 0, ctx->base.pc_next + a->offs); ++ ctx->base.is_jmp = DISAS_NORETURN; ++ return true; ++} ++ ++static bool trans_bl(DisasContext *ctx, arg_bl *a) ++{ ++ tcg_gen_movi_tl(cpu_gpr[1], make_address_pc(ctx, ctx->base.pc_next + 4)); ++ gen_goto_tb(ctx, 0, ctx->base.pc_next + a->offs); ++ ctx->base.is_jmp = DISAS_NORETURN; ++ return true; ++} ++ ++static bool trans_jirl(DisasContext *ctx, arg_jirl *a) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ TCGv addr = make_address_i(ctx, src1, a->imm); ++ tcg_gen_mov_tl(cpu_pc, addr); ++ tcg_gen_movi_tl(dest, make_address_pc(ctx, ctx->base.pc_next + 4)); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ tcg_gen_lookup_and_goto_ptr(); ++ ctx->base.is_jmp = DISAS_NORETURN; ++ return true; ++} ++ ++static void gen_bc(DisasContext *ctx, TCGv src1, TCGv src2, ++ target_long offs, TCGCond cond) ++{ ++ TCGLabel *l = gen_new_label(); ++ tcg_gen_brcond_tl(cond, src1, src2, l); ++ gen_goto_tb(ctx, 1, ctx->base.pc_next + 4); ++ gen_set_label(l); ++ gen_goto_tb(ctx, 0, ctx->base.pc_next + offs); ++ ctx->base.is_jmp = DISAS_NORETURN; ++} ++ ++static bool gen_rr_bc(DisasContext *ctx, arg_rr_offs *a, TCGCond cond) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rd, EXT_NONE); ++ ++ gen_bc(ctx, src1, src2, a->offs, cond); ++ return true; ++} ++ ++static bool gen_rz_bc(DisasContext *ctx, arg_r_offs *a, TCGCond cond) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = tcg_constant_tl(0); ++ ++ gen_bc(ctx, src1, src2, a->offs, cond); ++ return true; ++} ++ ++static bool gen_cz_bc(DisasContext *ctx, arg_c_offs *a, TCGCond cond) ++{ ++ TCGv src1 = tcg_temp_new(); ++ TCGv src2 = tcg_constant_tl(0); ++ ++ tcg_gen_ld8u_tl(src1, tcg_env, ++ offsetof(CPULoongArchState, cf[a->cj])); ++ gen_bc(ctx, src1, src2, a->offs, cond); ++ return true; ++} ++ ++TRANS(beq, ALL, gen_rr_bc, TCG_COND_EQ) ++TRANS(bne, ALL, gen_rr_bc, TCG_COND_NE) ++TRANS(blt, ALL, gen_rr_bc, TCG_COND_LT) ++TRANS(bge, ALL, gen_rr_bc, TCG_COND_GE) ++TRANS(bltu, ALL, gen_rr_bc, TCG_COND_LTU) ++TRANS(bgeu, ALL, gen_rr_bc, TCG_COND_GEU) ++TRANS(beqz, ALL, gen_rz_bc, TCG_COND_EQ) ++TRANS(bnez, ALL, gen_rz_bc, TCG_COND_NE) ++TRANS(bceqz, 64, gen_cz_bc, TCG_COND_EQ) ++TRANS(bcnez, 64, gen_cz_bc, TCG_COND_NE) +diff --git a/target/loongarch/tcg/insn_trans/trans_extra.c.inc b/target/loongarch/tcg/insn_trans/trans_extra.c.inc +new file mode 100644 +index 0000000..cfa361f +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_extra.c.inc +@@ -0,0 +1,107 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++static bool trans_break(DisasContext *ctx, arg_break *a) ++{ ++ generate_exception(ctx, EXCCODE_BRK); ++ return true; ++} ++ ++static bool trans_syscall(DisasContext *ctx, arg_syscall *a) ++{ ++ generate_exception(ctx, EXCCODE_SYS); ++ return true; ++} ++ ++static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d * a) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ ++ if (!avail_64(ctx)) { ++ return false; ++ } ++ ++ gen_helper_asrtle_d(tcg_env, src1, src2); ++ return true; ++} ++ ++static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ ++ if (!avail_64(ctx)) { ++ return false; ++ } ++ ++ gen_helper_asrtgt_d(tcg_env, src1, src2); ++ return true; ++} ++ ++static bool gen_rdtime(DisasContext *ctx, arg_rr *a, ++ bool word, bool high) ++{ ++ TCGv dst1 = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv dst2 = gpr_dst(ctx, a->rj, EXT_NONE); ++ ++ translator_io_start(&ctx->base); ++ gen_helper_rdtime_d(dst1, tcg_env); ++ if (word) { ++ tcg_gen_sextract_tl(dst1, dst1, high ? 32 : 0, 32); ++ } ++ tcg_gen_ld_i64(dst2, tcg_env, offsetof(CPULoongArchState, CSR_TID)); ++ ++ return true; ++} ++ ++static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a) ++{ ++ return gen_rdtime(ctx, a, 1, 0); ++} ++ ++static bool trans_rdtimeh_w(DisasContext *ctx, arg_rdtimeh_w *a) ++{ ++ return gen_rdtime(ctx, a, 1, 1); ++} ++ ++static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) ++{ ++ return gen_rdtime(ctx, a, 0, 0); ++} ++ ++static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ gen_helper_cpucfg(dest, tcg_env, src1); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static bool gen_crc(DisasContext *ctx, arg_rrr *a, ++ void (*func)(TCGv, TCGv, TCGv, TCGv), ++ TCGv tsz) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_SIGN); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ ++ func(dest, src2, src1, tsz); ++ gen_set_gpr(a->rd, dest, EXT_SIGN); ++ ++ return true; ++} ++ ++TRANS(crc_w_b_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(1)) ++TRANS(crc_w_h_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(2)) ++TRANS(crc_w_w_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(4)) ++TRANS(crc_w_d_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(8)) ++TRANS(crcc_w_b_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(1)) ++TRANS(crcc_w_h_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(2)) ++TRANS(crcc_w_w_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(4)) ++TRANS(crcc_w_d_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(8)) +diff --git a/target/loongarch/tcg/insn_trans/trans_farith.c.inc b/target/loongarch/tcg/insn_trans/trans_farith.c.inc +new file mode 100644 +index 0000000..f4a0dea +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_farith.c.inc +@@ -0,0 +1,207 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++#ifndef CONFIG_USER_ONLY ++#define CHECK_FPE do { \ ++ if ((ctx->base.tb->flags & HW_FLAGS_EUEN_FPE) == 0) { \ ++ generate_exception(ctx, EXCCODE_FPD); \ ++ return true; \ ++ } \ ++} while (0) ++#else ++#define CHECK_FPE ++#endif ++ ++static bool gen_fff(DisasContext *ctx, arg_fff *a, ++ void (*func)(TCGv, TCGv_env, TCGv, TCGv)) ++{ ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src1 = get_fpr(ctx, a->fj); ++ TCGv src2 = get_fpr(ctx, a->fk); ++ ++ CHECK_FPE; ++ ++ func(dest, tcg_env, src1, src2); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool gen_ff(DisasContext *ctx, arg_ff *a, ++ void (*func)(TCGv, TCGv_env, TCGv)) ++{ ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src = get_fpr(ctx, a->fj); ++ ++ CHECK_FPE; ++ ++ func(dest, tcg_env, src); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool gen_muladd(DisasContext *ctx, arg_ffff *a, ++ void (*func)(TCGv, TCGv_env, TCGv, TCGv, TCGv, TCGv_i32), ++ int flag) ++{ ++ TCGv_i32 tflag = tcg_constant_i32(flag); ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src1 = get_fpr(ctx, a->fj); ++ TCGv src2 = get_fpr(ctx, a->fk); ++ TCGv src3 = get_fpr(ctx, a->fa); ++ ++ CHECK_FPE; ++ ++ func(dest, tcg_env, src1, src2, src3, tflag); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool trans_fcopysign_s(DisasContext *ctx, arg_fcopysign_s *a) ++{ ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src1 = get_fpr(ctx, a->fk); ++ TCGv src2 = get_fpr(ctx, a->fj); ++ ++ if (!avail_FP_SP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ tcg_gen_deposit_i64(dest, src1, src2, 0, 31); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool trans_fcopysign_d(DisasContext *ctx, arg_fcopysign_d *a) ++{ ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src1 = get_fpr(ctx, a->fk); ++ TCGv src2 = get_fpr(ctx, a->fj); ++ ++ if (!avail_FP_DP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ tcg_gen_deposit_i64(dest, src1, src2, 0, 63); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool trans_fabs_s(DisasContext *ctx, arg_fabs_s *a) ++{ ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src = get_fpr(ctx, a->fj); ++ ++ if (!avail_FP_SP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ tcg_gen_andi_i64(dest, src, MAKE_64BIT_MASK(0, 31)); ++ gen_nanbox_s(dest, dest); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool trans_fabs_d(DisasContext *ctx, arg_fabs_d *a) ++{ ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src = get_fpr(ctx, a->fj); ++ ++ if (!avail_FP_DP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ tcg_gen_andi_i64(dest, src, MAKE_64BIT_MASK(0, 63)); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool trans_fneg_s(DisasContext *ctx, arg_fneg_s *a) ++{ ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src = get_fpr(ctx, a->fj); ++ ++ if (!avail_FP_SP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ tcg_gen_xori_i64(dest, src, 0x80000000); ++ gen_nanbox_s(dest, dest); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) ++{ ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src = get_fpr(ctx, a->fj); ++ ++ if (!avail_FP_DP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ tcg_gen_xori_i64(dest, src, 0x8000000000000000LL); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++TRANS(fadd_s, FP_SP, gen_fff, gen_helper_fadd_s) ++TRANS(fadd_d, FP_DP, gen_fff, gen_helper_fadd_d) ++TRANS(fsub_s, FP_SP, gen_fff, gen_helper_fsub_s) ++TRANS(fsub_d, FP_DP, gen_fff, gen_helper_fsub_d) ++TRANS(fmul_s, FP_SP, gen_fff, gen_helper_fmul_s) ++TRANS(fmul_d, FP_DP, gen_fff, gen_helper_fmul_d) ++TRANS(fdiv_s, FP_SP, gen_fff, gen_helper_fdiv_s) ++TRANS(fdiv_d, FP_DP, gen_fff, gen_helper_fdiv_d) ++TRANS(fmax_s, FP_SP, gen_fff, gen_helper_fmax_s) ++TRANS(fmax_d, FP_DP, gen_fff, gen_helper_fmax_d) ++TRANS(fmin_s, FP_SP, gen_fff, gen_helper_fmin_s) ++TRANS(fmin_d, FP_DP, gen_fff, gen_helper_fmin_d) ++TRANS(fmaxa_s, FP_SP, gen_fff, gen_helper_fmaxa_s) ++TRANS(fmaxa_d, FP_DP, gen_fff, gen_helper_fmaxa_d) ++TRANS(fmina_s, FP_SP, gen_fff, gen_helper_fmina_s) ++TRANS(fmina_d, FP_DP, gen_fff, gen_helper_fmina_d) ++TRANS(fscaleb_s, FP_SP, gen_fff, gen_helper_fscaleb_s) ++TRANS(fscaleb_d, FP_DP, gen_fff, gen_helper_fscaleb_d) ++TRANS(fsqrt_s, FP_SP, gen_ff, gen_helper_fsqrt_s) ++TRANS(fsqrt_d, FP_DP, gen_ff, gen_helper_fsqrt_d) ++TRANS(frecip_s, FP_SP, gen_ff, gen_helper_frecip_s) ++TRANS(frecip_d, FP_DP, gen_ff, gen_helper_frecip_d) ++TRANS(frsqrt_s, FP_SP, gen_ff, gen_helper_frsqrt_s) ++TRANS(frsqrt_d, FP_DP, gen_ff, gen_helper_frsqrt_d) ++TRANS(flogb_s, FP_SP, gen_ff, gen_helper_flogb_s) ++TRANS(flogb_d, FP_DP, gen_ff, gen_helper_flogb_d) ++TRANS(fclass_s, FP_SP, gen_ff, gen_helper_fclass_s) ++TRANS(fclass_d, FP_DP, gen_ff, gen_helper_fclass_d) ++TRANS(fmadd_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, 0) ++TRANS(fmadd_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, 0) ++TRANS(fmsub_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c) ++TRANS(fmsub_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c) ++TRANS(fnmadd_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_result) ++TRANS(fnmadd_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_result) ++TRANS(fnmsub_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, ++ float_muladd_negate_c | float_muladd_negate_result) ++TRANS(fnmsub_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, ++ float_muladd_negate_c | float_muladd_negate_result) +diff --git a/target/loongarch/tcg/insn_trans/trans_fcmp.c.inc b/target/loongarch/tcg/insn_trans/trans_fcmp.c.inc +new file mode 100644 +index 0000000..3babf69 +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_fcmp.c.inc +@@ -0,0 +1,72 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++/* bit0(signaling/quiet) bit1(lt) bit2(eq) bit3(un) bit4(neq) */ ++static uint32_t get_fcmp_flags(int cond) ++{ ++ uint32_t flags = 0; ++ ++ if (cond & 0x1) { ++ flags |= FCMP_LT; ++ } ++ if (cond & 0x2) { ++ flags |= FCMP_EQ; ++ } ++ if (cond & 0x4) { ++ flags |= FCMP_UN; ++ } ++ if (cond & 0x8) { ++ flags |= FCMP_GT | FCMP_LT; ++ } ++ return flags; ++} ++ ++static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) ++{ ++ TCGv var, src1, src2; ++ uint32_t flags; ++ void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); ++ ++ if (!avail_FP_SP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ var = tcg_temp_new(); ++ src1 = get_fpr(ctx, a->fj); ++ src2 = get_fpr(ctx, a->fk); ++ fn = (a->fcond & 1 ? gen_helper_fcmp_s_s : gen_helper_fcmp_c_s); ++ flags = get_fcmp_flags(a->fcond >> 1); ++ ++ fn(var, tcg_env, src1, src2, tcg_constant_i32(flags)); ++ ++ tcg_gen_st8_tl(var, tcg_env, offsetof(CPULoongArchState, cf[a->cd])); ++ return true; ++} ++ ++static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) ++{ ++ TCGv var, src1, src2; ++ uint32_t flags; ++ void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); ++ ++ if (!avail_FP_DP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ var = tcg_temp_new(); ++ src1 = get_fpr(ctx, a->fj); ++ src2 = get_fpr(ctx, a->fk); ++ fn = (a->fcond & 1 ? gen_helper_fcmp_s_d : gen_helper_fcmp_c_d); ++ flags = get_fcmp_flags(a->fcond >> 1); ++ ++ fn(var, tcg_env, src1, src2, tcg_constant_i32(flags)); ++ ++ tcg_gen_st8_tl(var, tcg_env, offsetof(CPULoongArchState, cf[a->cd])); ++ return true; ++} +diff --git a/target/loongarch/tcg/insn_trans/trans_fcnv.c.inc b/target/loongarch/tcg/insn_trans/trans_fcnv.c.inc +new file mode 100644 +index 0000000..833c059 +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_fcnv.c.inc +@@ -0,0 +1,33 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++TRANS(fcvt_s_d, FP_DP, gen_ff, gen_helper_fcvt_s_d) ++TRANS(fcvt_d_s, FP_DP, gen_ff, gen_helper_fcvt_d_s) ++TRANS(ftintrm_w_s, FP_SP, gen_ff, gen_helper_ftintrm_w_s) ++TRANS(ftintrm_w_d, FP_DP, gen_ff, gen_helper_ftintrm_w_d) ++TRANS(ftintrm_l_s, FP_SP, gen_ff, gen_helper_ftintrm_l_s) ++TRANS(ftintrm_l_d, FP_DP, gen_ff, gen_helper_ftintrm_l_d) ++TRANS(ftintrp_w_s, FP_SP, gen_ff, gen_helper_ftintrp_w_s) ++TRANS(ftintrp_w_d, FP_DP, gen_ff, gen_helper_ftintrp_w_d) ++TRANS(ftintrp_l_s, FP_SP, gen_ff, gen_helper_ftintrp_l_s) ++TRANS(ftintrp_l_d, FP_DP, gen_ff, gen_helper_ftintrp_l_d) ++TRANS(ftintrz_w_s, FP_SP, gen_ff, gen_helper_ftintrz_w_s) ++TRANS(ftintrz_w_d, FP_DP, gen_ff, gen_helper_ftintrz_w_d) ++TRANS(ftintrz_l_s, FP_SP, gen_ff, gen_helper_ftintrz_l_s) ++TRANS(ftintrz_l_d, FP_DP, gen_ff, gen_helper_ftintrz_l_d) ++TRANS(ftintrne_w_s, FP_SP, gen_ff, gen_helper_ftintrne_w_s) ++TRANS(ftintrne_w_d, FP_DP, gen_ff, gen_helper_ftintrne_w_d) ++TRANS(ftintrne_l_s, FP_SP, gen_ff, gen_helper_ftintrne_l_s) ++TRANS(ftintrne_l_d, FP_DP, gen_ff, gen_helper_ftintrne_l_d) ++TRANS(ftint_w_s, FP_SP, gen_ff, gen_helper_ftint_w_s) ++TRANS(ftint_w_d, FP_DP, gen_ff, gen_helper_ftint_w_d) ++TRANS(ftint_l_s, FP_SP, gen_ff, gen_helper_ftint_l_s) ++TRANS(ftint_l_d, FP_DP, gen_ff, gen_helper_ftint_l_d) ++TRANS(ffint_s_w, FP_SP, gen_ff, gen_helper_ffint_s_w) ++TRANS(ffint_s_l, FP_SP, gen_ff, gen_helper_ffint_s_l) ++TRANS(ffint_d_w, FP_DP, gen_ff, gen_helper_ffint_d_w) ++TRANS(ffint_d_l, FP_DP, gen_ff, gen_helper_ffint_d_l) ++TRANS(frint_s, FP_SP, gen_ff, gen_helper_frint_s) ++TRANS(frint_d, FP_DP, gen_ff, gen_helper_frint_d) +diff --git a/target/loongarch/tcg/insn_trans/trans_fmemory.c.inc b/target/loongarch/tcg/insn_trans/trans_fmemory.c.inc +new file mode 100644 +index 0000000..13452bc +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_fmemory.c.inc +@@ -0,0 +1,158 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++static void maybe_nanbox_load(TCGv freg, MemOp mop) ++{ ++ if ((mop & MO_SIZE) == MO_32) { ++ gen_nanbox_s(freg, freg); ++ } ++} ++ ++static bool gen_fload_i(DisasContext *ctx, arg_fr_i *a, MemOp mop) ++{ ++ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv dest = get_fpr(ctx, a->fd); ++ ++ CHECK_FPE; ++ ++ addr = make_address_i(ctx, addr, a->imm); ++ ++ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); ++ maybe_nanbox_load(dest, mop); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool gen_fstore_i(DisasContext *ctx, arg_fr_i *a, MemOp mop) ++{ ++ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src = get_fpr(ctx, a->fd); ++ ++ CHECK_FPE; ++ ++ addr = make_address_i(ctx, addr, a->imm); ++ ++ tcg_gen_qemu_st_tl(src, addr, ctx->mem_idx, mop); ++ ++ return true; ++} ++ ++static bool gen_floadx(DisasContext *ctx, arg_frr *a, MemOp mop) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv addr; ++ ++ CHECK_FPE; ++ ++ addr = make_address_x(ctx, src1, src2); ++ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); ++ maybe_nanbox_load(dest, mop); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool gen_fstorex(DisasContext *ctx, arg_frr *a, MemOp mop) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ TCGv src3 = get_fpr(ctx, a->fd); ++ TCGv addr; ++ ++ CHECK_FPE; ++ ++ addr = make_address_x(ctx, src1, src2); ++ tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); ++ ++ return true; ++} ++ ++static bool gen_fload_gt(DisasContext *ctx, arg_frr *a, MemOp mop) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv addr; ++ ++ CHECK_FPE; ++ ++ gen_helper_asrtgt_d(tcg_env, src1, src2); ++ addr = make_address_x(ctx, src1, src2); ++ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); ++ maybe_nanbox_load(dest, mop); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool gen_fstore_gt(DisasContext *ctx, arg_frr *a, MemOp mop) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ TCGv src3 = get_fpr(ctx, a->fd); ++ TCGv addr; ++ ++ CHECK_FPE; ++ ++ gen_helper_asrtgt_d(tcg_env, src1, src2); ++ addr = make_address_x(ctx, src1, src2); ++ tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); ++ ++ return true; ++} ++ ++static bool gen_fload_le(DisasContext *ctx, arg_frr *a, MemOp mop) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv addr; ++ ++ CHECK_FPE; ++ ++ gen_helper_asrtle_d(tcg_env, src1, src2); ++ addr = make_address_x(ctx, src1, src2); ++ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); ++ maybe_nanbox_load(dest, mop); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool gen_fstore_le(DisasContext *ctx, arg_frr *a, MemOp mop) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ TCGv src3 = get_fpr(ctx, a->fd); ++ TCGv addr; ++ ++ CHECK_FPE; ++ ++ gen_helper_asrtle_d(tcg_env, src1, src2); ++ addr = make_address_x(ctx, src1, src2); ++ tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); ++ ++ return true; ++} ++ ++TRANS(fld_s, FP_SP, gen_fload_i, MO_TEUL) ++TRANS(fst_s, FP_SP, gen_fstore_i, MO_TEUL) ++TRANS(fld_d, FP_DP, gen_fload_i, MO_TEUQ) ++TRANS(fst_d, FP_DP, gen_fstore_i, MO_TEUQ) ++TRANS(fldx_s, FP_SP, gen_floadx, MO_TEUL) ++TRANS(fldx_d, FP_DP, gen_floadx, MO_TEUQ) ++TRANS(fstx_s, FP_SP, gen_fstorex, MO_TEUL) ++TRANS(fstx_d, FP_DP, gen_fstorex, MO_TEUQ) ++TRANS(fldgt_s, FP_SP, gen_fload_gt, MO_TEUL) ++TRANS(fldgt_d, FP_DP, gen_fload_gt, MO_TEUQ) ++TRANS(fldle_s, FP_SP, gen_fload_le, MO_TEUL) ++TRANS(fldle_d, FP_DP, gen_fload_le, MO_TEUQ) ++TRANS(fstgt_s, FP_SP, gen_fstore_gt, MO_TEUL) ++TRANS(fstgt_d, FP_DP, gen_fstore_gt, MO_TEUQ) ++TRANS(fstle_s, FP_SP, gen_fstore_le, MO_TEUL) ++TRANS(fstle_d, FP_DP, gen_fstore_le, MO_TEUQ) +diff --git a/target/loongarch/tcg/insn_trans/trans_fmov.c.inc b/target/loongarch/tcg/insn_trans/trans_fmov.c.inc +new file mode 100644 +index 0000000..5cbd9d3 +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_fmov.c.inc +@@ -0,0 +1,224 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++static const uint32_t fcsr_mask[4] = { ++ UINT32_MAX, FCSR0_M1, FCSR0_M2, FCSR0_M3 ++}; ++ ++static bool trans_fsel(DisasContext *ctx, arg_fsel *a) ++{ ++ TCGv zero = tcg_constant_tl(0); ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src1 = get_fpr(ctx, a->fj); ++ TCGv src2 = get_fpr(ctx, a->fk); ++ TCGv cond; ++ ++ if (!avail_FP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ cond = tcg_temp_new(); ++ tcg_gen_ld8u_tl(cond, tcg_env, offsetof(CPULoongArchState, cf[a->ca])); ++ tcg_gen_movcond_tl(TCG_COND_EQ, dest, cond, zero, src1, src2); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool gen_f2f(DisasContext *ctx, arg_ff *a, ++ void (*func)(TCGv, TCGv), bool nanbox) ++{ ++ TCGv dest = get_fpr(ctx, a->fd); ++ TCGv src = get_fpr(ctx, a->fj); ++ ++ CHECK_FPE; ++ ++ func(dest, src); ++ if (nanbox) { ++ gen_nanbox_s(dest, dest); ++ } ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool gen_r2f(DisasContext *ctx, arg_fr *a, ++ void (*func)(TCGv, TCGv)) ++{ ++ TCGv src = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv dest = get_fpr(ctx, a->fd); ++ ++ if (!avail_FP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ func(dest, src); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool gen_f2r(DisasContext *ctx, arg_rf *a, ++ void (*func)(TCGv, TCGv)) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src = get_fpr(ctx, a->fj); ++ ++ if (!avail_FP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ func(dest, src); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) ++{ ++ uint32_t mask = fcsr_mask[a->fcsrd]; ++ TCGv Rj = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ if (!avail_FP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ if (mask == UINT32_MAX) { ++ tcg_gen_st32_i64(Rj, tcg_env, offsetof(CPULoongArchState, fcsr0)); ++ } else { ++ TCGv_i32 fcsr0 = tcg_temp_new_i32(); ++ TCGv_i32 temp = tcg_temp_new_i32(); ++ ++ tcg_gen_ld_i32(fcsr0, tcg_env, offsetof(CPULoongArchState, fcsr0)); ++ tcg_gen_extrl_i64_i32(temp, Rj); ++ tcg_gen_andi_i32(temp, temp, mask); ++ tcg_gen_andi_i32(fcsr0, fcsr0, ~mask); ++ tcg_gen_or_i32(fcsr0, fcsr0, temp); ++ tcg_gen_st_i32(fcsr0, tcg_env, offsetof(CPULoongArchState, fcsr0)); ++ } ++ ++ /* ++ * Install the new rounding mode to fpu_status, if changed. ++ * Note that FCSR3 is exactly the rounding mode field. ++ */ ++ if (mask & FCSR0_M3) { ++ gen_helper_set_rounding_mode(tcg_env); ++ } ++ return true; ++} ++ ++static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ ++ if (!avail_FP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ tcg_gen_ld32u_i64(dest, tcg_env, offsetof(CPULoongArchState, fcsr0)); ++ tcg_gen_andi_i64(dest, dest, fcsr_mask[a->fcsrs]); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static void gen_movgr2fr_w(TCGv dest, TCGv src) ++{ ++ tcg_gen_deposit_i64(dest, dest, src, 0, 32); ++} ++ ++static void gen_movgr2frh_w(TCGv dest, TCGv src) ++{ ++ tcg_gen_deposit_i64(dest, dest, src, 32, 32); ++} ++ ++static void gen_movfrh2gr_s(TCGv dest, TCGv src) ++{ ++ tcg_gen_sextract_tl(dest, src, 32, 32); ++} ++ ++static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) ++{ ++ TCGv t0; ++ TCGv src = get_fpr(ctx, a->fj); ++ ++ if (!avail_FP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ t0 = tcg_temp_new(); ++ tcg_gen_andi_tl(t0, src, 0x1); ++ tcg_gen_st8_tl(t0, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); ++ ++ return true; ++} ++ ++static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) ++{ ++ TCGv dest = get_fpr(ctx, a->fd); ++ ++ if (!avail_FP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ tcg_gen_ld8u_tl(dest, tcg_env, ++ offsetof(CPULoongArchState, cf[a->cj & 0x7])); ++ set_fpr(a->fd, dest); ++ ++ return true; ++} ++ ++static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) ++{ ++ TCGv t0; ++ ++ if (!avail_FP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ t0 = tcg_temp_new(); ++ tcg_gen_andi_tl(t0, gpr_src(ctx, a->rj, EXT_NONE), 0x1); ++ tcg_gen_st8_tl(t0, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); ++ ++ return true; ++} ++ ++static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) ++{ ++ if (!avail_FP(ctx)) { ++ return false; ++ } ++ ++ CHECK_FPE; ++ ++ tcg_gen_ld8u_tl(gpr_dst(ctx, a->rd, EXT_NONE), tcg_env, ++ offsetof(CPULoongArchState, cf[a->cj & 0x7])); ++ return true; ++} ++ ++TRANS(fmov_s, FP_SP, gen_f2f, tcg_gen_mov_tl, true) ++TRANS(fmov_d, FP_DP, gen_f2f, tcg_gen_mov_tl, false) ++TRANS(movgr2fr_w, FP_SP, gen_r2f, gen_movgr2fr_w) ++TRANS(movgr2fr_d, 64, gen_r2f, tcg_gen_mov_tl) ++TRANS(movgr2frh_w, FP_DP, gen_r2f, gen_movgr2frh_w) ++TRANS(movfr2gr_s, FP_SP, gen_f2r, tcg_gen_ext32s_tl) ++TRANS(movfr2gr_d, 64, gen_f2r, tcg_gen_mov_tl) ++TRANS(movfrh2gr_s, FP_DP, gen_f2r, gen_movfrh2gr_s) +diff --git a/target/loongarch/tcg/insn_trans/trans_memory.c.inc b/target/loongarch/tcg/insn_trans/trans_memory.c.inc +new file mode 100644 +index 0000000..42f4e74 +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_memory.c.inc +@@ -0,0 +1,194 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++static bool gen_load(DisasContext *ctx, arg_rr_i *a, MemOp mop) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ addr = make_address_i(ctx, addr, a->imm); ++ ++ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ return true; ++} ++ ++static bool gen_store(DisasContext *ctx, arg_rr_i *a, MemOp mop) ++{ ++ TCGv data = gpr_src(ctx, a->rd, EXT_NONE); ++ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ addr = make_address_i(ctx, addr, a->imm); ++ ++ tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); ++ return true; ++} ++ ++static bool gen_loadx(DisasContext *ctx, arg_rrr *a, MemOp mop) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ TCGv addr = make_address_x(ctx, src1, src2); ++ ++ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static bool gen_storex(DisasContext *ctx, arg_rrr *a, MemOp mop) ++{ ++ TCGv data = gpr_src(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ TCGv addr = make_address_x(ctx, src1, src2); ++ ++ tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); ++ ++ return true; ++} ++ ++static bool gen_load_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ ++ gen_helper_asrtgt_d(tcg_env, src1, src2); ++ src1 = make_address_i(ctx, src1, 0); ++ tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static bool gen_load_le(DisasContext *ctx, arg_rrr *a, MemOp mop) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ ++ gen_helper_asrtle_d(tcg_env, src1, src2); ++ src1 = make_address_i(ctx, src1, 0); ++ tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++static bool gen_store_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) ++{ ++ TCGv data = gpr_src(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ ++ gen_helper_asrtgt_d(tcg_env, src1, src2); ++ src1 = make_address_i(ctx, src1, 0); ++ tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); ++ ++ return true; ++} ++ ++static bool gen_store_le(DisasContext *ctx, arg_rrr *a, MemOp mop) ++{ ++ TCGv data = gpr_src(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ ++ gen_helper_asrtle_d(tcg_env, src1, src2); ++ src1 = make_address_i(ctx, src1, 0); ++ tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); ++ ++ return true; ++} ++ ++static bool trans_preld(DisasContext *ctx, arg_preld *a) ++{ ++ return true; ++} ++ ++static bool trans_preldx(DisasContext *ctx, arg_preldx * a) ++{ ++ return true; ++} ++ ++static bool trans_dbar(DisasContext *ctx, arg_dbar * a) ++{ ++ tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); ++ return true; ++} ++ ++static bool trans_ibar(DisasContext *ctx, arg_ibar *a) ++{ ++ ctx->base.is_jmp = DISAS_STOP; ++ return true; ++} ++ ++static bool gen_ldptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ addr = make_address_i(ctx, addr, a->imm); ++ ++ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ return true; ++} ++ ++static bool gen_stptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) ++{ ++ TCGv data = gpr_src(ctx, a->rd, EXT_NONE); ++ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ addr = make_address_i(ctx, addr, a->imm); ++ ++ tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); ++ return true; ++} ++ ++TRANS(ld_b, ALL, gen_load, MO_SB) ++TRANS(ld_h, ALL, gen_load, MO_TESW) ++TRANS(ld_w, ALL, gen_load, MO_TESL) ++TRANS(ld_d, 64, gen_load, MO_TEUQ) ++TRANS(st_b, ALL, gen_store, MO_UB) ++TRANS(st_h, ALL, gen_store, MO_TEUW) ++TRANS(st_w, ALL, gen_store, MO_TEUL) ++TRANS(st_d, 64, gen_store, MO_TEUQ) ++TRANS(ld_bu, ALL, gen_load, MO_UB) ++TRANS(ld_hu, ALL, gen_load, MO_TEUW) ++TRANS(ld_wu, 64, gen_load, MO_TEUL) ++TRANS(ldx_b, 64, gen_loadx, MO_SB) ++TRANS(ldx_h, 64, gen_loadx, MO_TESW) ++TRANS(ldx_w, 64, gen_loadx, MO_TESL) ++TRANS(ldx_d, 64, gen_loadx, MO_TEUQ) ++TRANS(stx_b, 64, gen_storex, MO_UB) ++TRANS(stx_h, 64, gen_storex, MO_TEUW) ++TRANS(stx_w, 64, gen_storex, MO_TEUL) ++TRANS(stx_d, 64, gen_storex, MO_TEUQ) ++TRANS(ldx_bu, 64, gen_loadx, MO_UB) ++TRANS(ldx_hu, 64, gen_loadx, MO_TEUW) ++TRANS(ldx_wu, 64, gen_loadx, MO_TEUL) ++TRANS(ldptr_w, 64, gen_ldptr, MO_TESL) ++TRANS(stptr_w, 64, gen_stptr, MO_TEUL) ++TRANS(ldptr_d, 64, gen_ldptr, MO_TEUQ) ++TRANS(stptr_d, 64, gen_stptr, MO_TEUQ) ++TRANS(ldgt_b, 64, gen_load_gt, MO_SB) ++TRANS(ldgt_h, 64, gen_load_gt, MO_TESW) ++TRANS(ldgt_w, 64, gen_load_gt, MO_TESL) ++TRANS(ldgt_d, 64, gen_load_gt, MO_TEUQ) ++TRANS(ldle_b, 64, gen_load_le, MO_SB) ++TRANS(ldle_h, 64, gen_load_le, MO_TESW) ++TRANS(ldle_w, 64, gen_load_le, MO_TESL) ++TRANS(ldle_d, 64, gen_load_le, MO_TEUQ) ++TRANS(stgt_b, 64, gen_store_gt, MO_UB) ++TRANS(stgt_h, 64, gen_store_gt, MO_TEUW) ++TRANS(stgt_w, 64, gen_store_gt, MO_TEUL) ++TRANS(stgt_d, 64, gen_store_gt, MO_TEUQ) ++TRANS(stle_b, 64, gen_store_le, MO_UB) ++TRANS(stle_h, 64, gen_store_le, MO_TEUW) ++TRANS(stle_w, 64, gen_store_le, MO_TEUL) ++TRANS(stle_d, 64, gen_store_le, MO_TEUQ) +diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc +new file mode 100644 +index 0000000..01d4572 +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc +@@ -0,0 +1,498 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ * ++ * LoongArch translation routines for the privileged instructions. ++ */ ++ ++#include "cpu-csr.h" ++ ++#ifdef CONFIG_USER_ONLY ++ ++#define GEN_FALSE_TRANS(name) \ ++static bool trans_##name(DisasContext *ctx, arg_##name * a) \ ++{ \ ++ return false; \ ++} ++ ++GEN_FALSE_TRANS(csrrd) ++GEN_FALSE_TRANS(csrwr) ++GEN_FALSE_TRANS(csrxchg) ++GEN_FALSE_TRANS(iocsrrd_b) ++GEN_FALSE_TRANS(iocsrrd_h) ++GEN_FALSE_TRANS(iocsrrd_w) ++GEN_FALSE_TRANS(iocsrrd_d) ++GEN_FALSE_TRANS(iocsrwr_b) ++GEN_FALSE_TRANS(iocsrwr_h) ++GEN_FALSE_TRANS(iocsrwr_w) ++GEN_FALSE_TRANS(iocsrwr_d) ++GEN_FALSE_TRANS(tlbsrch) ++GEN_FALSE_TRANS(tlbrd) ++GEN_FALSE_TRANS(tlbwr) ++GEN_FALSE_TRANS(tlbfill) ++GEN_FALSE_TRANS(tlbclr) ++GEN_FALSE_TRANS(tlbflush) ++GEN_FALSE_TRANS(invtlb) ++GEN_FALSE_TRANS(cacop) ++GEN_FALSE_TRANS(ldpte) ++GEN_FALSE_TRANS(lddir) ++GEN_FALSE_TRANS(ertn) ++GEN_FALSE_TRANS(dbcl) ++GEN_FALSE_TRANS(idle) ++ ++#else ++ ++typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env); ++typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src); ++ ++typedef struct { ++ int offset; ++ int flags; ++ GenCSRRead readfn; ++ GenCSRWrite writefn; ++} CSRInfo; ++ ++enum { ++ CSRFL_READONLY = (1 << 0), ++ CSRFL_EXITTB = (1 << 1), ++ CSRFL_IO = (1 << 2), ++}; ++ ++#define CSR_OFF_FUNCS(NAME, FL, RD, WR) \ ++ [LOONGARCH_CSR_##NAME] = { \ ++ .offset = offsetof(CPULoongArchState, CSR_##NAME), \ ++ .flags = FL, .readfn = RD, .writefn = WR \ ++ } ++ ++#define CSR_OFF_ARRAY(NAME, N) \ ++ [LOONGARCH_CSR_##NAME(N)] = { \ ++ .offset = offsetof(CPULoongArchState, CSR_##NAME[N]), \ ++ .flags = 0, .readfn = NULL, .writefn = NULL \ ++ } ++ ++#define CSR_OFF_FLAGS(NAME, FL) \ ++ CSR_OFF_FUNCS(NAME, FL, NULL, NULL) ++ ++#define CSR_OFF(NAME) \ ++ CSR_OFF_FLAGS(NAME, 0) ++ ++static const CSRInfo csr_info[] = { ++ CSR_OFF_FLAGS(CRMD, CSRFL_EXITTB), ++ CSR_OFF(PRMD), ++ CSR_OFF_FLAGS(EUEN, CSRFL_EXITTB), ++ CSR_OFF_FLAGS(MISC, CSRFL_READONLY), ++ CSR_OFF(ECFG), ++ CSR_OFF_FUNCS(ESTAT, CSRFL_EXITTB, NULL, gen_helper_csrwr_estat), ++ CSR_OFF(ERA), ++ CSR_OFF(BADV), ++ CSR_OFF_FLAGS(BADI, CSRFL_READONLY), ++ CSR_OFF(EENTRY), ++ CSR_OFF(TLBIDX), ++ CSR_OFF(TLBEHI), ++ CSR_OFF(TLBELO0), ++ CSR_OFF(TLBELO1), ++ CSR_OFF_FUNCS(ASID, CSRFL_EXITTB, NULL, gen_helper_csrwr_asid), ++ CSR_OFF(PGDL), ++ CSR_OFF(PGDH), ++ CSR_OFF_FUNCS(PGD, CSRFL_READONLY, gen_helper_csrrd_pgd, NULL), ++ CSR_OFF(PWCL), ++ CSR_OFF(PWCH), ++ CSR_OFF(STLBPS), ++ CSR_OFF(RVACFG), ++ CSR_OFF_FUNCS(CPUID, CSRFL_READONLY, gen_helper_csrrd_cpuid, NULL), ++ CSR_OFF_FLAGS(PRCFG1, CSRFL_READONLY), ++ CSR_OFF_FLAGS(PRCFG2, CSRFL_READONLY), ++ CSR_OFF_FLAGS(PRCFG3, CSRFL_READONLY), ++ CSR_OFF_ARRAY(SAVE, 0), ++ CSR_OFF_ARRAY(SAVE, 1), ++ CSR_OFF_ARRAY(SAVE, 2), ++ CSR_OFF_ARRAY(SAVE, 3), ++ CSR_OFF_ARRAY(SAVE, 4), ++ CSR_OFF_ARRAY(SAVE, 5), ++ CSR_OFF_ARRAY(SAVE, 6), ++ CSR_OFF_ARRAY(SAVE, 7), ++ CSR_OFF_ARRAY(SAVE, 8), ++ CSR_OFF_ARRAY(SAVE, 9), ++ CSR_OFF_ARRAY(SAVE, 10), ++ CSR_OFF_ARRAY(SAVE, 11), ++ CSR_OFF_ARRAY(SAVE, 12), ++ CSR_OFF_ARRAY(SAVE, 13), ++ CSR_OFF_ARRAY(SAVE, 14), ++ CSR_OFF_ARRAY(SAVE, 15), ++ CSR_OFF(TID), ++ CSR_OFF_FUNCS(TCFG, CSRFL_IO, NULL, gen_helper_csrwr_tcfg), ++ CSR_OFF_FUNCS(TVAL, CSRFL_READONLY | CSRFL_IO, gen_helper_csrrd_tval, NULL), ++ CSR_OFF(CNTC), ++ CSR_OFF_FUNCS(TICLR, CSRFL_IO, NULL, gen_helper_csrwr_ticlr), ++ CSR_OFF(LLBCTL), ++ CSR_OFF(IMPCTL1), ++ CSR_OFF(IMPCTL2), ++ CSR_OFF(TLBRENTRY), ++ CSR_OFF(TLBRBADV), ++ CSR_OFF(TLBRERA), ++ CSR_OFF(TLBRSAVE), ++ CSR_OFF(TLBRELO0), ++ CSR_OFF(TLBRELO1), ++ CSR_OFF(TLBREHI), ++ CSR_OFF(TLBRPRMD), ++ CSR_OFF(MERRCTL), ++ CSR_OFF(MERRINFO1), ++ CSR_OFF(MERRINFO2), ++ CSR_OFF(MERRENTRY), ++ CSR_OFF(MERRERA), ++ CSR_OFF(MERRSAVE), ++ CSR_OFF(CTAG), ++ CSR_OFF_ARRAY(DMW, 0), ++ CSR_OFF_ARRAY(DMW, 1), ++ CSR_OFF_ARRAY(DMW, 2), ++ CSR_OFF_ARRAY(DMW, 3), ++ CSR_OFF(DBG), ++ CSR_OFF(DERA), ++ CSR_OFF(DSAVE), ++}; ++ ++static bool check_plv(DisasContext *ctx) ++{ ++ if (ctx->plv == MMU_PLV_USER) { ++ generate_exception(ctx, EXCCODE_IPE); ++ return true; ++ } ++ return false; ++} ++ ++static const CSRInfo *get_csr(unsigned csr_num) ++{ ++ const CSRInfo *csr; ++ ++ if (csr_num >= ARRAY_SIZE(csr_info)) { ++ return NULL; ++ } ++ csr = &csr_info[csr_num]; ++ if (csr->offset == 0) { ++ return NULL; ++ } ++ return csr; ++} ++ ++static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write) ++{ ++ if ((csr->flags & CSRFL_READONLY) && write) { ++ return false; ++ } ++ if ((csr->flags & CSRFL_IO) && translator_io_start(&ctx->base)) { ++ ctx->base.is_jmp = DISAS_EXIT_UPDATE; ++ } else if ((csr->flags & CSRFL_EXITTB) && write) { ++ ctx->base.is_jmp = DISAS_EXIT_UPDATE; ++ } ++ return true; ++} ++ ++static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a) ++{ ++ TCGv dest; ++ const CSRInfo *csr; ++ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ csr = get_csr(a->csr); ++ if (csr == NULL) { ++ /* CSR is undefined: read as 0. */ ++ dest = tcg_constant_tl(0); ++ } else { ++ check_csr_flags(ctx, csr, false); ++ dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ if (csr->readfn) { ++ csr->readfn(dest, tcg_env); ++ } else { ++ tcg_gen_ld_tl(dest, tcg_env, csr->offset); ++ } ++ } ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ return true; ++} ++ ++static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a) ++{ ++ TCGv dest, src1; ++ const CSRInfo *csr; ++ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ csr = get_csr(a->csr); ++ if (csr == NULL) { ++ /* CSR is undefined: write ignored, read old_value as 0. */ ++ gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); ++ return true; ++ } ++ if (!check_csr_flags(ctx, csr, true)) { ++ /* CSR is readonly: trap. */ ++ return false; ++ } ++ src1 = gpr_src(ctx, a->rd, EXT_NONE); ++ if (csr->writefn) { ++ dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ csr->writefn(dest, tcg_env, src1); ++ } else { ++ dest = tcg_temp_new(); ++ tcg_gen_ld_tl(dest, tcg_env, csr->offset); ++ tcg_gen_st_tl(src1, tcg_env, csr->offset); ++ } ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ return true; ++} ++ ++static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) ++{ ++ TCGv src1, mask, oldv, newv, temp; ++ const CSRInfo *csr; ++ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ csr = get_csr(a->csr); ++ if (csr == NULL) { ++ /* CSR is undefined: write ignored, read old_value as 0. */ ++ gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); ++ return true; ++ } ++ ++ if (!check_csr_flags(ctx, csr, true)) { ++ /* CSR is readonly: trap. */ ++ return false; ++ } ++ ++ /* So far only readonly csrs have readfn. */ ++ assert(csr->readfn == NULL); ++ ++ src1 = gpr_src(ctx, a->rd, EXT_NONE); ++ mask = gpr_src(ctx, a->rj, EXT_NONE); ++ oldv = tcg_temp_new(); ++ newv = tcg_temp_new(); ++ temp = tcg_temp_new(); ++ ++ tcg_gen_ld_tl(oldv, tcg_env, csr->offset); ++ tcg_gen_and_tl(newv, src1, mask); ++ tcg_gen_andc_tl(temp, oldv, mask); ++ tcg_gen_or_tl(newv, newv, temp); ++ ++ if (csr->writefn) { ++ csr->writefn(oldv, tcg_env, newv); ++ } else { ++ tcg_gen_st_tl(newv, tcg_env, csr->offset); ++ } ++ gen_set_gpr(a->rd, oldv, EXT_NONE); ++ return true; ++} ++ ++static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a, ++ void (*func)(TCGv, TCGv_ptr, TCGv)) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ func(dest, tcg_env, src1); ++ return true; ++} ++ ++static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a, ++ void (*func)(TCGv_ptr, TCGv, TCGv)) ++{ ++ TCGv val = gpr_src(ctx, a->rd, EXT_NONE); ++ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ func(tcg_env, addr, val); ++ return true; ++} ++ ++TRANS(iocsrrd_b, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_b) ++TRANS(iocsrrd_h, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_h) ++TRANS(iocsrrd_w, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_w) ++TRANS(iocsrrd_d, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_d) ++TRANS(iocsrwr_b, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_b) ++TRANS(iocsrwr_h, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_h) ++TRANS(iocsrwr_w, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_w) ++TRANS(iocsrwr_d, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_d) ++ ++static void check_mmu_idx(DisasContext *ctx) ++{ ++ if (ctx->mem_idx != MMU_IDX_DA) { ++ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4); ++ ctx->base.is_jmp = DISAS_EXIT; ++ } ++} ++ ++static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a) ++{ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ gen_helper_tlbsrch(tcg_env); ++ return true; ++} ++ ++static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a) ++{ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ gen_helper_tlbrd(tcg_env); ++ return true; ++} ++ ++static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a) ++{ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ gen_helper_tlbwr(tcg_env); ++ check_mmu_idx(ctx); ++ return true; ++} ++ ++static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a) ++{ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ gen_helper_tlbfill(tcg_env); ++ check_mmu_idx(ctx); ++ return true; ++} ++ ++static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a) ++{ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ gen_helper_tlbclr(tcg_env); ++ check_mmu_idx(ctx); ++ return true; ++} ++ ++static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a) ++{ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ gen_helper_tlbflush(tcg_env); ++ check_mmu_idx(ctx); ++ return true; ++} ++ ++static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) ++{ ++ TCGv rj = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv rk = gpr_src(ctx, a->rk, EXT_NONE); ++ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ ++ switch (a->imm) { ++ case 0: ++ case 1: ++ gen_helper_invtlb_all(tcg_env); ++ break; ++ case 2: ++ gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(1)); ++ break; ++ case 3: ++ gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(0)); ++ break; ++ case 4: ++ gen_helper_invtlb_all_asid(tcg_env, rj); ++ break; ++ case 5: ++ gen_helper_invtlb_page_asid(tcg_env, rj, rk); ++ break; ++ case 6: ++ gen_helper_invtlb_page_asid_or_g(tcg_env, rj, rk); ++ break; ++ default: ++ return false; ++ } ++ ctx->base.is_jmp = DISAS_STOP; ++ return true; ++} ++ ++static bool trans_cacop(DisasContext *ctx, arg_cacop *a) ++{ ++ /* Treat the cacop as a nop */ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ return true; ++} ++ ++static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) ++{ ++ TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ if (!avail_LSPW(ctx)) { ++ return true; ++ } ++ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ gen_helper_ldpte(tcg_env, src1, tcg_constant_tl(a->imm), mem_idx); ++ return true; ++} ++ ++static bool trans_lddir(DisasContext *ctx, arg_lddir *a) ++{ ++ TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx); ++ TCGv src = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ ++ if (!avail_LSPW(ctx)) { ++ return true; ++ } ++ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ gen_helper_lddir(dest, tcg_env, src, tcg_constant_tl(a->imm), mem_idx); ++ return true; ++} ++ ++static bool trans_ertn(DisasContext *ctx, arg_ertn *a) ++{ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ gen_helper_ertn(tcg_env); ++ ctx->base.is_jmp = DISAS_EXIT; ++ return true; ++} ++ ++static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) ++{ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ generate_exception(ctx, EXCCODE_DBP); ++ return true; ++} ++ ++static bool trans_idle(DisasContext *ctx, arg_idle *a) ++{ ++ if (check_plv(ctx)) { ++ return false; ++ } ++ ++ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4); ++ gen_helper_idle(tcg_env); ++ ctx->base.is_jmp = DISAS_NORETURN; ++ return true; ++} ++#endif +diff --git a/target/loongarch/tcg/insn_trans/trans_shift.c.inc b/target/loongarch/tcg/insn_trans/trans_shift.c.inc +new file mode 100644 +index 0000000..2f4bd6f +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_shift.c.inc +@@ -0,0 +1,99 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++static void gen_sll_w(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ tcg_gen_andi_tl(t0, src2, 0x1f); ++ tcg_gen_shl_tl(dest, src1, t0); ++} ++ ++static void gen_srl_w(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ tcg_gen_andi_tl(t0, src2, 0x1f); ++ tcg_gen_shr_tl(dest, src1, t0); ++} ++ ++static void gen_sra_w(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ tcg_gen_andi_tl(t0, src2, 0x1f); ++ tcg_gen_sar_tl(dest, src1, t0); ++} ++ ++static void gen_sll_d(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ tcg_gen_andi_tl(t0, src2, 0x3f); ++ tcg_gen_shl_tl(dest, src1, t0); ++} ++ ++static void gen_srl_d(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ tcg_gen_andi_tl(t0, src2, 0x3f); ++ tcg_gen_shr_tl(dest, src1, t0); ++} ++ ++static void gen_sra_d(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ tcg_gen_andi_tl(t0, src2, 0x3f); ++ tcg_gen_sar_tl(dest, src1, t0); ++} ++ ++static void gen_rotr_w(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv_i32 t1 = tcg_temp_new_i32(); ++ TCGv_i32 t2 = tcg_temp_new_i32(); ++ TCGv t0 = tcg_temp_new(); ++ ++ tcg_gen_andi_tl(t0, src2, 0x1f); ++ ++ tcg_gen_trunc_tl_i32(t1, src1); ++ tcg_gen_trunc_tl_i32(t2, t0); ++ ++ tcg_gen_rotr_i32(t1, t1, t2); ++ tcg_gen_ext_i32_tl(dest, t1); ++} ++ ++static void gen_rotr_d(TCGv dest, TCGv src1, TCGv src2) ++{ ++ TCGv t0 = tcg_temp_new(); ++ tcg_gen_andi_tl(t0, src2, 0x3f); ++ tcg_gen_rotr_tl(dest, src1, t0); ++} ++ ++static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) ++{ ++ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO); ++ ++ if (!avail_64(ctx)) { ++ return false; ++ } ++ ++ tcg_gen_sextract_tl(dest, src1, a->imm, 32 - a->imm); ++ gen_set_gpr(a->rd, dest, EXT_NONE); ++ ++ return true; ++} ++ ++TRANS(sll_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) ++TRANS(srl_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_srl_w) ++TRANS(sra_w, ALL, gen_rrr, EXT_SIGN, EXT_NONE, EXT_SIGN, gen_sra_w) ++TRANS(sll_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sll_d) ++TRANS(srl_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_srl_d) ++TRANS(sra_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sra_d) ++TRANS(rotr_w, 64, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_rotr_w) ++TRANS(rotr_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rotr_d) ++TRANS(slli_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) ++TRANS(slli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) ++TRANS(srli_w, ALL, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) ++TRANS(srli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) ++TRANS(srai_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) ++TRANS(rotri_w, 64, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) ++TRANS(rotri_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) +diff --git a/target/loongarch/tcg/insn_trans/trans_vec.c.inc b/target/loongarch/tcg/insn_trans/trans_vec.c.inc +new file mode 100644 +index 0000000..92b1d22 +--- /dev/null ++++ b/target/loongarch/tcg/insn_trans/trans_vec.c.inc +@@ -0,0 +1,5511 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch vector translate functions ++ * Copyright (c) 2022-2023 Loongson Technology Corporation Limited ++ */ ++ ++static bool check_vec(DisasContext *ctx, uint32_t oprsz) ++{ ++ if ((oprsz == 16) && ((ctx->base.tb->flags & HW_FLAGS_EUEN_SXE) == 0)) { ++ generate_exception(ctx, EXCCODE_SXD); ++ return false; ++ } ++ ++ if ((oprsz == 32) && ((ctx->base.tb->flags & HW_FLAGS_EUEN_ASXE) == 0)) { ++ generate_exception(ctx, EXCCODE_ASXD); ++ return false; ++ } ++ ++ return true; ++} ++ ++static bool gen_vvvv_ptr_vl(DisasContext *ctx, arg_vvvv *a, uint32_t oprsz, ++ gen_helper_gvec_4_ptr *fn) ++{ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_4_ptr(vec_full_offset(a->vd), ++ vec_full_offset(a->vj), ++ vec_full_offset(a->vk), ++ vec_full_offset(a->va), ++ tcg_env, ++ oprsz, ctx->vl / 8, 0, fn); ++ return true; ++} ++ ++static bool gen_vvvv_ptr(DisasContext *ctx, arg_vvvv *a, ++ gen_helper_gvec_4_ptr *fn) ++{ ++ return gen_vvvv_ptr_vl(ctx, a, 16, fn); ++} ++ ++static bool gen_xxxx_ptr(DisasContext *ctx, arg_vvvv *a, ++ gen_helper_gvec_4_ptr *fn) ++{ ++ return gen_vvvv_ptr_vl(ctx, a, 32, fn); ++} ++ ++static bool gen_vvvv_vl(DisasContext *ctx, arg_vvvv *a, uint32_t oprsz, ++ gen_helper_gvec_4 *fn) ++{ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_4_ool(vec_full_offset(a->vd), ++ vec_full_offset(a->vj), ++ vec_full_offset(a->vk), ++ vec_full_offset(a->va), ++ oprsz, ctx->vl / 8, 0, fn); ++ return true; ++} ++ ++static bool gen_vvvv(DisasContext *ctx, arg_vvvv *a, ++ gen_helper_gvec_4 *fn) ++{ ++ return gen_vvvv_vl(ctx, a, 16, fn); ++} ++ ++static bool gen_xxxx(DisasContext *ctx, arg_vvvv *a, ++ gen_helper_gvec_4 *fn) ++{ ++ return gen_vvvv_vl(ctx, a, 32, fn); ++} ++ ++static bool gen_vvv_ptr_vl(DisasContext *ctx, arg_vvv *a, uint32_t oprsz, ++ gen_helper_gvec_3_ptr *fn) ++{ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ tcg_gen_gvec_3_ptr(vec_full_offset(a->vd), ++ vec_full_offset(a->vj), ++ vec_full_offset(a->vk), ++ tcg_env, ++ oprsz, ctx->vl / 8, 0, fn); ++ return true; ++} ++ ++static bool gen_vvv_ptr(DisasContext *ctx, arg_vvv *a, ++ gen_helper_gvec_3_ptr *fn) ++{ ++ return gen_vvv_ptr_vl(ctx, a, 16, fn); ++} ++ ++static bool gen_xxx_ptr(DisasContext *ctx, arg_vvv *a, ++ gen_helper_gvec_3_ptr *fn) ++{ ++ return gen_vvv_ptr_vl(ctx, a, 32, fn); ++} ++ ++static bool gen_vvv_vl(DisasContext *ctx, arg_vvv *a, uint32_t oprsz, ++ gen_helper_gvec_3 *fn) ++{ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_3_ool(vec_full_offset(a->vd), ++ vec_full_offset(a->vj), ++ vec_full_offset(a->vk), ++ oprsz, ctx->vl / 8, 0, fn); ++ return true; ++} ++ ++static bool gen_vvv(DisasContext *ctx, arg_vvv *a, gen_helper_gvec_3 *fn) ++{ ++ return gen_vvv_vl(ctx, a, 16, fn); ++} ++ ++static bool gen_xxx(DisasContext *ctx, arg_vvv *a, gen_helper_gvec_3 *fn) ++{ ++ return gen_vvv_vl(ctx, a, 32, fn); ++} ++ ++static bool gen_vv_ptr_vl(DisasContext *ctx, arg_vv *a, uint32_t oprsz, ++ gen_helper_gvec_2_ptr *fn) ++{ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_2_ptr(vec_full_offset(a->vd), ++ vec_full_offset(a->vj), ++ tcg_env, ++ oprsz, ctx->vl / 8, 0, fn); ++ return true; ++} ++ ++static bool gen_vv_ptr(DisasContext *ctx, arg_vv *a, ++ gen_helper_gvec_2_ptr *fn) ++{ ++ return gen_vv_ptr_vl(ctx, a, 16, fn); ++} ++ ++static bool gen_xx_ptr(DisasContext *ctx, arg_vv *a, ++ gen_helper_gvec_2_ptr *fn) ++{ ++ return gen_vv_ptr_vl(ctx, a, 32, fn); ++} ++ ++static bool gen_vv_vl(DisasContext *ctx, arg_vv *a, uint32_t oprsz, ++ gen_helper_gvec_2 *fn) ++{ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_2_ool(vec_full_offset(a->vd), ++ vec_full_offset(a->vj), ++ oprsz, ctx->vl / 8, 0, fn); ++ return true; ++} ++ ++static bool gen_vv(DisasContext *ctx, arg_vv *a, gen_helper_gvec_2 *fn) ++{ ++ return gen_vv_vl(ctx, a, 16, fn); ++} ++ ++static bool gen_xx(DisasContext *ctx, arg_vv *a, gen_helper_gvec_2 *fn) ++{ ++ return gen_vv_vl(ctx, a, 32, fn); ++} ++ ++static bool gen_vv_i_vl(DisasContext *ctx, arg_vv_i *a, uint32_t oprsz, ++ gen_helper_gvec_2i *fn) ++{ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_2i_ool(vec_full_offset(a->vd), ++ vec_full_offset(a->vj), ++ tcg_constant_i64(a->imm), ++ oprsz, ctx->vl / 8, 0, fn); ++ return true; ++} ++ ++static bool gen_vv_i(DisasContext *ctx, arg_vv_i *a, gen_helper_gvec_2i *fn) ++{ ++ return gen_vv_i_vl(ctx, a, 16, fn); ++} ++ ++static bool gen_xx_i(DisasContext *ctx, arg_vv_i *a, gen_helper_gvec_2i *fn) ++{ ++ return gen_vv_i_vl(ctx, a, 32, fn); ++} ++ ++static bool gen_cv_vl(DisasContext *ctx, arg_cv *a, uint32_t sz, ++ void (*func)(TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32)) ++{ ++ if (!check_vec(ctx, sz)) { ++ return true; ++ } ++ ++ TCGv_i32 vj = tcg_constant_i32(a->vj); ++ TCGv_i32 cd = tcg_constant_i32(a->cd); ++ TCGv_i32 oprsz = tcg_constant_i32(sz); ++ ++ func(tcg_env, oprsz, cd, vj); ++ return true; ++} ++ ++static bool gen_cv(DisasContext *ctx, arg_cv *a, ++ void (*func)(TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32)) ++{ ++ return gen_cv_vl(ctx, a, 16, func); ++} ++ ++static bool gen_cx(DisasContext *ctx, arg_cv *a, ++ void (*func)(TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32)) ++{ ++ return gen_cv_vl(ctx, a, 32, func); ++} ++ ++static bool gvec_vvv_vl(DisasContext *ctx, arg_vvv *a, ++ uint32_t oprsz, MemOp mop, ++ void (*func)(unsigned, uint32_t, uint32_t, ++ uint32_t, uint32_t, uint32_t)) ++{ ++ uint32_t vd_ofs = vec_full_offset(a->vd); ++ uint32_t vj_ofs = vec_full_offset(a->vj); ++ uint32_t vk_ofs = vec_full_offset(a->vk); ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ func(mop, vd_ofs, vj_ofs, vk_ofs, oprsz, ctx->vl / 8); ++ return true; ++} ++ ++static bool gvec_vvv(DisasContext *ctx, arg_vvv *a, MemOp mop, ++ void (*func)(unsigned, uint32_t, uint32_t, ++ uint32_t, uint32_t, uint32_t)) ++{ ++ return gvec_vvv_vl(ctx, a, 16, mop, func); ++} ++ ++static bool gvec_xxx(DisasContext *ctx, arg_vvv *a, MemOp mop, ++ void (*func)(unsigned, uint32_t, uint32_t, ++ uint32_t, uint32_t, uint32_t)) ++{ ++ return gvec_vvv_vl(ctx, a, 32, mop, func); ++} ++ ++static bool gvec_vv_vl(DisasContext *ctx, arg_vv *a, ++ uint32_t oprsz, MemOp mop, ++ void (*func)(unsigned, uint32_t, uint32_t, ++ uint32_t, uint32_t)) ++{ ++ uint32_t vd_ofs = vec_full_offset(a->vd); ++ uint32_t vj_ofs = vec_full_offset(a->vj); ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ func(mop, vd_ofs, vj_ofs, oprsz, ctx->vl / 8); ++ return true; ++} ++ ++ ++static bool gvec_vv(DisasContext *ctx, arg_vv *a, MemOp mop, ++ void (*func)(unsigned, uint32_t, uint32_t, ++ uint32_t, uint32_t)) ++{ ++ return gvec_vv_vl(ctx, a, 16, mop, func); ++} ++ ++static bool gvec_xx(DisasContext *ctx, arg_vv *a, MemOp mop, ++ void (*func)(unsigned, uint32_t, uint32_t, ++ uint32_t, uint32_t)) ++{ ++ return gvec_vv_vl(ctx, a, 32, mop, func); ++} ++ ++static bool gvec_vv_i_vl(DisasContext *ctx, arg_vv_i *a, ++ uint32_t oprsz, MemOp mop, ++ void (*func)(unsigned, uint32_t, uint32_t, ++ int64_t, uint32_t, uint32_t)) ++{ ++ uint32_t vd_ofs = vec_full_offset(a->vd); ++ uint32_t vj_ofs = vec_full_offset(a->vj); ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ func(mop, vd_ofs, vj_ofs, a->imm, oprsz, ctx->vl / 8); ++ return true; ++} ++ ++static bool gvec_vv_i(DisasContext *ctx, arg_vv_i *a, MemOp mop, ++ void (*func)(unsigned, uint32_t, uint32_t, ++ int64_t, uint32_t, uint32_t)) ++{ ++ return gvec_vv_i_vl(ctx, a, 16, mop, func); ++} ++ ++static bool gvec_xx_i(DisasContext *ctx, arg_vv_i *a, MemOp mop, ++ void (*func)(unsigned, uint32_t, uint32_t, ++ int64_t, uint32_t, uint32_t)) ++{ ++ return gvec_vv_i_vl(ctx,a, 32, mop, func); ++} ++ ++static bool gvec_subi_vl(DisasContext *ctx, arg_vv_i *a, ++ uint32_t oprsz, MemOp mop) ++{ ++ uint32_t vd_ofs = vec_full_offset(a->vd); ++ uint32_t vj_ofs = vec_full_offset(a->vj); ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_addi(mop, vd_ofs, vj_ofs, -a->imm, oprsz, ctx->vl / 8); ++ return true; ++} ++ ++static bool gvec_subi(DisasContext *ctx, arg_vv_i *a, MemOp mop) ++{ ++ return gvec_subi_vl(ctx, a, 16, mop); ++} ++ ++static bool gvec_xsubi(DisasContext *ctx, arg_vv_i *a, MemOp mop) ++{ ++ return gvec_subi_vl(ctx, a, 32, mop); ++} ++ ++TRANS(vadd_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_add) ++TRANS(vadd_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_add) ++TRANS(vadd_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_add) ++TRANS(vadd_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_add) ++TRANS(xvadd_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_add) ++TRANS(xvadd_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_add) ++TRANS(xvadd_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_add) ++TRANS(xvadd_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_add) ++ ++static bool gen_vaddsub_q_vl(DisasContext *ctx, arg_vvv *a, uint32_t oprsz, ++ void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, ++ TCGv_i64, TCGv_i64, TCGv_i64)) ++{ ++ int i; ++ TCGv_i64 rh, rl, ah, al, bh, bl; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ rh = tcg_temp_new_i64(); ++ rl = tcg_temp_new_i64(); ++ ah = tcg_temp_new_i64(); ++ al = tcg_temp_new_i64(); ++ bh = tcg_temp_new_i64(); ++ bl = tcg_temp_new_i64(); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ get_vreg64(ah, a->vj, 1 + i * 2); ++ get_vreg64(al, a->vj, i * 2); ++ get_vreg64(bh, a->vk, 1 + i * 2); ++ get_vreg64(bl, a->vk, i * 2); ++ ++ func(rl, rh, al, ah, bl, bh); ++ ++ set_vreg64(rh, a->vd, 1 + i * 2); ++ set_vreg64(rl, a->vd, i * 2); ++ } ++ return true; ++} ++ ++static bool gen_vaddsub_q(DisasContext *ctx, arg_vvv *a, ++ void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, ++ TCGv_i64, TCGv_i64, TCGv_i64)) ++{ ++ return gen_vaddsub_q_vl(ctx, a, 16, func); ++} ++ ++static bool gen_xvaddsub_q(DisasContext *ctx, arg_vvv *a, ++ void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, ++ TCGv_i64, TCGv_i64, TCGv_i64)) ++{ ++ return gen_vaddsub_q_vl(ctx, a, 32, func); ++} ++ ++TRANS(vsub_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_sub) ++TRANS(vsub_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_sub) ++TRANS(vsub_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_sub) ++TRANS(vsub_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_sub) ++TRANS(xvsub_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_sub) ++TRANS(xvsub_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_sub) ++TRANS(xvsub_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_sub) ++TRANS(xvsub_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_sub) ++ ++TRANS(vadd_q, LSX, gen_vaddsub_q, tcg_gen_add2_i64) ++TRANS(vsub_q, LSX, gen_vaddsub_q, tcg_gen_sub2_i64) ++TRANS(xvadd_q, LASX, gen_xvaddsub_q, tcg_gen_add2_i64) ++TRANS(xvsub_q, LASX, gen_xvaddsub_q, tcg_gen_sub2_i64) ++ ++TRANS(vaddi_bu, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_addi) ++TRANS(vaddi_hu, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_addi) ++TRANS(vaddi_wu, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_addi) ++TRANS(vaddi_du, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_addi) ++TRANS(vsubi_bu, LSX, gvec_subi, MO_8) ++TRANS(vsubi_hu, LSX, gvec_subi, MO_16) ++TRANS(vsubi_wu, LSX, gvec_subi, MO_32) ++TRANS(vsubi_du, LSX, gvec_subi, MO_64) ++TRANS(xvaddi_bu, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_addi) ++TRANS(xvaddi_hu, LASX, gvec_xx_i, MO_16, tcg_gen_gvec_addi) ++TRANS(xvaddi_wu, LASX, gvec_xx_i, MO_32, tcg_gen_gvec_addi) ++TRANS(xvaddi_du, LASX, gvec_xx_i, MO_64, tcg_gen_gvec_addi) ++TRANS(xvsubi_bu, LASX, gvec_xsubi, MO_8) ++TRANS(xvsubi_hu, LASX, gvec_xsubi, MO_16) ++TRANS(xvsubi_wu, LASX, gvec_xsubi, MO_32) ++TRANS(xvsubi_du, LASX, gvec_xsubi, MO_64) ++ ++TRANS(vneg_b, LSX, gvec_vv, MO_8, tcg_gen_gvec_neg) ++TRANS(vneg_h, LSX, gvec_vv, MO_16, tcg_gen_gvec_neg) ++TRANS(vneg_w, LSX, gvec_vv, MO_32, tcg_gen_gvec_neg) ++TRANS(vneg_d, LSX, gvec_vv, MO_64, tcg_gen_gvec_neg) ++TRANS(xvneg_b, LASX, gvec_xx, MO_8, tcg_gen_gvec_neg) ++TRANS(xvneg_h, LASX, gvec_xx, MO_16, tcg_gen_gvec_neg) ++TRANS(xvneg_w, LASX, gvec_xx, MO_32, tcg_gen_gvec_neg) ++TRANS(xvneg_d, LASX, gvec_xx, MO_64, tcg_gen_gvec_neg) ++ ++TRANS(vsadd_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_ssadd) ++TRANS(vsadd_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_ssadd) ++TRANS(vsadd_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_ssadd) ++TRANS(vsadd_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_ssadd) ++TRANS(vsadd_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_usadd) ++TRANS(vsadd_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_usadd) ++TRANS(vsadd_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_usadd) ++TRANS(vsadd_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_usadd) ++TRANS(vssub_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_sssub) ++TRANS(vssub_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_sssub) ++TRANS(vssub_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_sssub) ++TRANS(vssub_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_sssub) ++TRANS(vssub_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_ussub) ++TRANS(vssub_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_ussub) ++TRANS(vssub_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_ussub) ++TRANS(vssub_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_ussub) ++ ++TRANS(xvsadd_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_ssadd) ++TRANS(xvsadd_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_ssadd) ++TRANS(xvsadd_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_ssadd) ++TRANS(xvsadd_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_ssadd) ++TRANS(xvsadd_bu, LASX, gvec_xxx, MO_8, tcg_gen_gvec_usadd) ++TRANS(xvsadd_hu, LASX, gvec_xxx, MO_16, tcg_gen_gvec_usadd) ++TRANS(xvsadd_wu, LASX, gvec_xxx, MO_32, tcg_gen_gvec_usadd) ++TRANS(xvsadd_du, LASX, gvec_xxx, MO_64, tcg_gen_gvec_usadd) ++TRANS(xvssub_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_sssub) ++TRANS(xvssub_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_sssub) ++TRANS(xvssub_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_sssub) ++TRANS(xvssub_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_sssub) ++TRANS(xvssub_bu, LASX, gvec_xxx, MO_8, tcg_gen_gvec_ussub) ++TRANS(xvssub_hu, LASX, gvec_xxx, MO_16, tcg_gen_gvec_ussub) ++TRANS(xvssub_wu, LASX, gvec_xxx, MO_32, tcg_gen_gvec_ussub) ++TRANS(xvssub_du, LASX, gvec_xxx, MO_64, tcg_gen_gvec_ussub) ++ ++TRANS(vhaddw_h_b, LSX, gen_vvv, gen_helper_vhaddw_h_b) ++TRANS(vhaddw_w_h, LSX, gen_vvv, gen_helper_vhaddw_w_h) ++TRANS(vhaddw_d_w, LSX, gen_vvv, gen_helper_vhaddw_d_w) ++TRANS(vhaddw_q_d, LSX, gen_vvv, gen_helper_vhaddw_q_d) ++TRANS(vhaddw_hu_bu, LSX, gen_vvv, gen_helper_vhaddw_hu_bu) ++TRANS(vhaddw_wu_hu, LSX, gen_vvv, gen_helper_vhaddw_wu_hu) ++TRANS(vhaddw_du_wu, LSX, gen_vvv, gen_helper_vhaddw_du_wu) ++TRANS(vhaddw_qu_du, LSX, gen_vvv, gen_helper_vhaddw_qu_du) ++TRANS(vhsubw_h_b, LSX, gen_vvv, gen_helper_vhsubw_h_b) ++TRANS(vhsubw_w_h, LSX, gen_vvv, gen_helper_vhsubw_w_h) ++TRANS(vhsubw_d_w, LSX, gen_vvv, gen_helper_vhsubw_d_w) ++TRANS(vhsubw_q_d, LSX, gen_vvv, gen_helper_vhsubw_q_d) ++TRANS(vhsubw_hu_bu, LSX, gen_vvv, gen_helper_vhsubw_hu_bu) ++TRANS(vhsubw_wu_hu, LSX, gen_vvv, gen_helper_vhsubw_wu_hu) ++TRANS(vhsubw_du_wu, LSX, gen_vvv, gen_helper_vhsubw_du_wu) ++TRANS(vhsubw_qu_du, LSX, gen_vvv, gen_helper_vhsubw_qu_du) ++ ++TRANS(xvhaddw_h_b, LASX, gen_xxx, gen_helper_vhaddw_h_b) ++TRANS(xvhaddw_w_h, LASX, gen_xxx, gen_helper_vhaddw_w_h) ++TRANS(xvhaddw_d_w, LASX, gen_xxx, gen_helper_vhaddw_d_w) ++TRANS(xvhaddw_q_d, LASX, gen_xxx, gen_helper_vhaddw_q_d) ++TRANS(xvhaddw_hu_bu, LASX, gen_xxx, gen_helper_vhaddw_hu_bu) ++TRANS(xvhaddw_wu_hu, LASX, gen_xxx, gen_helper_vhaddw_wu_hu) ++TRANS(xvhaddw_du_wu, LASX, gen_xxx, gen_helper_vhaddw_du_wu) ++TRANS(xvhaddw_qu_du, LASX, gen_xxx, gen_helper_vhaddw_qu_du) ++TRANS(xvhsubw_h_b, LASX, gen_xxx, gen_helper_vhsubw_h_b) ++TRANS(xvhsubw_w_h, LASX, gen_xxx, gen_helper_vhsubw_w_h) ++TRANS(xvhsubw_d_w, LASX, gen_xxx, gen_helper_vhsubw_d_w) ++TRANS(xvhsubw_q_d, LASX, gen_xxx, gen_helper_vhsubw_q_d) ++TRANS(xvhsubw_hu_bu, LASX, gen_xxx, gen_helper_vhsubw_hu_bu) ++TRANS(xvhsubw_wu_hu, LASX, gen_xxx, gen_helper_vhsubw_wu_hu) ++TRANS(xvhsubw_du_wu, LASX, gen_xxx, gen_helper_vhsubw_du_wu) ++TRANS(xvhsubw_qu_du, LASX, gen_xxx, gen_helper_vhsubw_qu_du) ++ ++static void gen_vaddwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ ++ /* Sign-extend the even elements from a */ ++ tcg_gen_shli_vec(vece, t1, a, halfbits); ++ tcg_gen_sari_vec(vece, t1, t1, halfbits); ++ ++ /* Sign-extend the even elements from b */ ++ tcg_gen_shli_vec(vece, t2, b, halfbits); ++ tcg_gen_sari_vec(vece, t2, t2, halfbits); ++ ++ tcg_gen_add_vec(vece, t, t1, t2); ++} ++ ++static void gen_vaddwev_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_ext16s_i32(t1, a); ++ tcg_gen_ext16s_i32(t2, b); ++ tcg_gen_add_i32(t, t1, t2); ++} ++ ++static void gen_vaddwev_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_ext32s_i64(t1, a); ++ tcg_gen_ext32s_i64(t2, b); ++ tcg_gen_add_i64(t, t1, t2); ++} ++ ++static void do_vaddwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shli_vec, INDEX_op_sari_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vaddwev_s, ++ .fno = gen_helper_vaddwev_h_b, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vaddwev_w_h, ++ .fniv = gen_vaddwev_s, ++ .fno = gen_helper_vaddwev_w_h, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vaddwev_d_w, ++ .fniv = gen_vaddwev_s, ++ .fno = gen_helper_vaddwev_d_w, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ { ++ .fno = gen_helper_vaddwev_q_d, ++ .vece = MO_128 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vaddwev_h_b, LSX, gvec_vvv, MO_8, do_vaddwev_s) ++TRANS(vaddwev_w_h, LSX, gvec_vvv, MO_16, do_vaddwev_s) ++TRANS(vaddwev_d_w, LSX, gvec_vvv, MO_32, do_vaddwev_s) ++TRANS(vaddwev_q_d, LSX, gvec_vvv, MO_64, do_vaddwev_s) ++TRANS(xvaddwev_h_b, LASX, gvec_xxx, MO_8, do_vaddwev_s) ++TRANS(xvaddwev_w_h, LASX, gvec_xxx, MO_16, do_vaddwev_s) ++TRANS(xvaddwev_d_w, LASX, gvec_xxx, MO_32, do_vaddwev_s) ++TRANS(xvaddwev_q_d, LASX, gvec_xxx, MO_64, do_vaddwev_s) ++ ++static void gen_vaddwod_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_sari_i32(t1, a, 16); ++ tcg_gen_sari_i32(t2, b, 16); ++ tcg_gen_add_i32(t, t1, t2); ++} ++ ++static void gen_vaddwod_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_sari_i64(t1, a, 32); ++ tcg_gen_sari_i64(t2, b, 32); ++ tcg_gen_add_i64(t, t1, t2); ++} ++ ++static void gen_vaddwod_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ ++ /* Sign-extend the odd elements for vector */ ++ tcg_gen_sari_vec(vece, t1, a, halfbits); ++ tcg_gen_sari_vec(vece, t2, b, halfbits); ++ ++ tcg_gen_add_vec(vece, t, t1, t2); ++} ++ ++static void do_vaddwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_sari_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vaddwod_s, ++ .fno = gen_helper_vaddwod_h_b, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vaddwod_w_h, ++ .fniv = gen_vaddwod_s, ++ .fno = gen_helper_vaddwod_w_h, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vaddwod_d_w, ++ .fniv = gen_vaddwod_s, ++ .fno = gen_helper_vaddwod_d_w, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ { ++ .fno = gen_helper_vaddwod_q_d, ++ .vece = MO_128 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vaddwod_h_b, LSX, gvec_vvv, MO_8, do_vaddwod_s) ++TRANS(vaddwod_w_h, LSX, gvec_vvv, MO_16, do_vaddwod_s) ++TRANS(vaddwod_d_w, LSX, gvec_vvv, MO_32, do_vaddwod_s) ++TRANS(vaddwod_q_d, LSX, gvec_vvv, MO_64, do_vaddwod_s) ++TRANS(xvaddwod_h_b, LASX, gvec_xxx, MO_8, do_vaddwod_s) ++TRANS(xvaddwod_w_h, LASX, gvec_xxx, MO_16, do_vaddwod_s) ++TRANS(xvaddwod_d_w, LASX, gvec_xxx, MO_32, do_vaddwod_s) ++TRANS(xvaddwod_q_d, LASX, gvec_xxx, MO_64, do_vaddwod_s) ++ ++ ++static void gen_vsubwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ ++ /* Sign-extend the even elements from a */ ++ tcg_gen_shli_vec(vece, t1, a, halfbits); ++ tcg_gen_sari_vec(vece, t1, t1, halfbits); ++ ++ /* Sign-extend the even elements from b */ ++ tcg_gen_shli_vec(vece, t2, b, halfbits); ++ tcg_gen_sari_vec(vece, t2, t2, halfbits); ++ ++ tcg_gen_sub_vec(vece, t, t1, t2); ++} ++ ++static void gen_vsubwev_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_ext16s_i32(t1, a); ++ tcg_gen_ext16s_i32(t2, b); ++ tcg_gen_sub_i32(t, t1, t2); ++} ++ ++static void gen_vsubwev_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_ext32s_i64(t1, a); ++ tcg_gen_ext32s_i64(t2, b); ++ tcg_gen_sub_i64(t, t1, t2); ++} ++ ++static void do_vsubwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shli_vec, INDEX_op_sari_vec, INDEX_op_sub_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vsubwev_s, ++ .fno = gen_helper_vsubwev_h_b, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vsubwev_w_h, ++ .fniv = gen_vsubwev_s, ++ .fno = gen_helper_vsubwev_w_h, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vsubwev_d_w, ++ .fniv = gen_vsubwev_s, ++ .fno = gen_helper_vsubwev_d_w, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ { ++ .fno = gen_helper_vsubwev_q_d, ++ .vece = MO_128 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vsubwev_h_b, LSX, gvec_vvv, MO_8, do_vsubwev_s) ++TRANS(vsubwev_w_h, LSX, gvec_vvv, MO_16, do_vsubwev_s) ++TRANS(vsubwev_d_w, LSX, gvec_vvv, MO_32, do_vsubwev_s) ++TRANS(vsubwev_q_d, LSX, gvec_vvv, MO_64, do_vsubwev_s) ++TRANS(xvsubwev_h_b, LASX, gvec_xxx, MO_8, do_vsubwev_s) ++TRANS(xvsubwev_w_h, LASX, gvec_xxx, MO_16, do_vsubwev_s) ++TRANS(xvsubwev_d_w, LASX, gvec_xxx, MO_32, do_vsubwev_s) ++TRANS(xvsubwev_q_d, LASX, gvec_xxx, MO_64, do_vsubwev_s) ++ ++static void gen_vsubwod_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ ++ /* Sign-extend the odd elements for vector */ ++ tcg_gen_sari_vec(vece, t1, a, halfbits); ++ tcg_gen_sari_vec(vece, t2, b, halfbits); ++ ++ tcg_gen_sub_vec(vece, t, t1, t2); ++} ++ ++static void gen_vsubwod_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_sari_i32(t1, a, 16); ++ tcg_gen_sari_i32(t2, b, 16); ++ tcg_gen_sub_i32(t, t1, t2); ++} ++ ++static void gen_vsubwod_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_sari_i64(t1, a, 32); ++ tcg_gen_sari_i64(t2, b, 32); ++ tcg_gen_sub_i64(t, t1, t2); ++} ++ ++static void do_vsubwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_sari_vec, INDEX_op_sub_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vsubwod_s, ++ .fno = gen_helper_vsubwod_h_b, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vsubwod_w_h, ++ .fniv = gen_vsubwod_s, ++ .fno = gen_helper_vsubwod_w_h, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vsubwod_d_w, ++ .fniv = gen_vsubwod_s, ++ .fno = gen_helper_vsubwod_d_w, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ { ++ .fno = gen_helper_vsubwod_q_d, ++ .vece = MO_128 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vsubwod_h_b, LSX, gvec_vvv, MO_8, do_vsubwod_s) ++TRANS(vsubwod_w_h, LSX, gvec_vvv, MO_16, do_vsubwod_s) ++TRANS(vsubwod_d_w, LSX, gvec_vvv, MO_32, do_vsubwod_s) ++TRANS(vsubwod_q_d, LSX, gvec_vvv, MO_64, do_vsubwod_s) ++TRANS(xvsubwod_h_b, LASX, gvec_xxx, MO_8, do_vsubwod_s) ++TRANS(xvsubwod_w_h, LASX, gvec_xxx, MO_16, do_vsubwod_s) ++TRANS(xvsubwod_d_w, LASX, gvec_xxx, MO_32, do_vsubwod_s) ++TRANS(xvsubwod_q_d, LASX, gvec_xxx, MO_64, do_vsubwod_s) ++ ++static void gen_vaddwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, t3; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ t3 = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); ++ tcg_gen_and_vec(vece, t1, a, t3); ++ tcg_gen_and_vec(vece, t2, b, t3); ++ tcg_gen_add_vec(vece, t, t1, t2); ++} ++ ++static void gen_vaddwev_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_ext16u_i32(t1, a); ++ tcg_gen_ext16u_i32(t2, b); ++ tcg_gen_add_i32(t, t1, t2); ++} ++ ++static void gen_vaddwev_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_ext32u_i64(t1, a); ++ tcg_gen_ext32u_i64(t2, b); ++ tcg_gen_add_i64(t, t1, t2); ++} ++ ++static void do_vaddwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vaddwev_u, ++ .fno = gen_helper_vaddwev_h_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vaddwev_w_hu, ++ .fniv = gen_vaddwev_u, ++ .fno = gen_helper_vaddwev_w_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vaddwev_d_wu, ++ .fniv = gen_vaddwev_u, ++ .fno = gen_helper_vaddwev_d_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ { ++ .fno = gen_helper_vaddwev_q_du, ++ .vece = MO_128 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vaddwev_h_bu, LSX, gvec_vvv, MO_8, do_vaddwev_u) ++TRANS(vaddwev_w_hu, LSX, gvec_vvv, MO_16, do_vaddwev_u) ++TRANS(vaddwev_d_wu, LSX, gvec_vvv, MO_32, do_vaddwev_u) ++TRANS(vaddwev_q_du, LSX, gvec_vvv, MO_64, do_vaddwev_u) ++TRANS(xvaddwev_h_bu, LASX, gvec_xxx, MO_8, do_vaddwev_u) ++TRANS(xvaddwev_w_hu, LASX, gvec_xxx, MO_16, do_vaddwev_u) ++TRANS(xvaddwev_d_wu, LASX, gvec_xxx, MO_32, do_vaddwev_u) ++TRANS(xvaddwev_q_du, LASX, gvec_xxx, MO_64, do_vaddwev_u) ++ ++static void gen_vaddwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ ++ /* Zero-extend the odd elements for vector */ ++ tcg_gen_shri_vec(vece, t1, a, halfbits); ++ tcg_gen_shri_vec(vece, t2, b, halfbits); ++ ++ tcg_gen_add_vec(vece, t, t1, t2); ++} ++ ++static void gen_vaddwod_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_shri_i32(t1, a, 16); ++ tcg_gen_shri_i32(t2, b, 16); ++ tcg_gen_add_i32(t, t1, t2); ++} ++ ++static void gen_vaddwod_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_shri_i64(t1, a, 32); ++ tcg_gen_shri_i64(t2, b, 32); ++ tcg_gen_add_i64(t, t1, t2); ++} ++ ++static void do_vaddwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shri_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vaddwod_u, ++ .fno = gen_helper_vaddwod_h_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vaddwod_w_hu, ++ .fniv = gen_vaddwod_u, ++ .fno = gen_helper_vaddwod_w_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vaddwod_d_wu, ++ .fniv = gen_vaddwod_u, ++ .fno = gen_helper_vaddwod_d_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ { ++ .fno = gen_helper_vaddwod_q_du, ++ .vece = MO_128 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vaddwod_h_bu, LSX, gvec_vvv, MO_8, do_vaddwod_u) ++TRANS(vaddwod_w_hu, LSX, gvec_vvv, MO_16, do_vaddwod_u) ++TRANS(vaddwod_d_wu, LSX, gvec_vvv, MO_32, do_vaddwod_u) ++TRANS(vaddwod_q_du, LSX, gvec_vvv, MO_64, do_vaddwod_u) ++TRANS(xvaddwod_h_bu, LASX, gvec_xxx, MO_8, do_vaddwod_u) ++TRANS(xvaddwod_w_hu, LASX, gvec_xxx, MO_16, do_vaddwod_u) ++TRANS(xvaddwod_d_wu, LASX, gvec_xxx, MO_32, do_vaddwod_u) ++TRANS(xvaddwod_q_du, LASX, gvec_xxx, MO_64, do_vaddwod_u) ++ ++static void gen_vsubwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, t3; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ t3 = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); ++ tcg_gen_and_vec(vece, t1, a, t3); ++ tcg_gen_and_vec(vece, t2, b, t3); ++ tcg_gen_sub_vec(vece, t, t1, t2); ++} ++ ++static void gen_vsubwev_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_ext16u_i32(t1, a); ++ tcg_gen_ext16u_i32(t2, b); ++ tcg_gen_sub_i32(t, t1, t2); ++} ++ ++static void gen_vsubwev_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_ext32u_i64(t1, a); ++ tcg_gen_ext32u_i64(t2, b); ++ tcg_gen_sub_i64(t, t1, t2); ++} ++ ++static void do_vsubwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_sub_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vsubwev_u, ++ .fno = gen_helper_vsubwev_h_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vsubwev_w_hu, ++ .fniv = gen_vsubwev_u, ++ .fno = gen_helper_vsubwev_w_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vsubwev_d_wu, ++ .fniv = gen_vsubwev_u, ++ .fno = gen_helper_vsubwev_d_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ { ++ .fno = gen_helper_vsubwev_q_du, ++ .vece = MO_128 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vsubwev_h_bu, LSX, gvec_vvv, MO_8, do_vsubwev_u) ++TRANS(vsubwev_w_hu, LSX, gvec_vvv, MO_16, do_vsubwev_u) ++TRANS(vsubwev_d_wu, LSX, gvec_vvv, MO_32, do_vsubwev_u) ++TRANS(vsubwev_q_du, LSX, gvec_vvv, MO_64, do_vsubwev_u) ++TRANS(xvsubwev_h_bu, LASX, gvec_xxx, MO_8, do_vsubwev_u) ++TRANS(xvsubwev_w_hu, LASX, gvec_xxx, MO_16, do_vsubwev_u) ++TRANS(xvsubwev_d_wu, LASX, gvec_xxx, MO_32, do_vsubwev_u) ++TRANS(xvsubwev_q_du, LASX, gvec_xxx, MO_64, do_vsubwev_u) ++ ++static void gen_vsubwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ ++ /* Zero-extend the odd elements for vector */ ++ tcg_gen_shri_vec(vece, t1, a, halfbits); ++ tcg_gen_shri_vec(vece, t2, b, halfbits); ++ ++ tcg_gen_sub_vec(vece, t, t1, t2); ++} ++ ++static void gen_vsubwod_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_shri_i32(t1, a, 16); ++ tcg_gen_shri_i32(t2, b, 16); ++ tcg_gen_sub_i32(t, t1, t2); ++} ++ ++static void gen_vsubwod_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_shri_i64(t1, a, 32); ++ tcg_gen_shri_i64(t2, b, 32); ++ tcg_gen_sub_i64(t, t1, t2); ++} ++ ++static void do_vsubwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shri_vec, INDEX_op_sub_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vsubwod_u, ++ .fno = gen_helper_vsubwod_h_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vsubwod_w_hu, ++ .fniv = gen_vsubwod_u, ++ .fno = gen_helper_vsubwod_w_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vsubwod_d_wu, ++ .fniv = gen_vsubwod_u, ++ .fno = gen_helper_vsubwod_d_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ { ++ .fno = gen_helper_vsubwod_q_du, ++ .vece = MO_128 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vsubwod_h_bu, LSX, gvec_vvv, MO_8, do_vsubwod_u) ++TRANS(vsubwod_w_hu, LSX, gvec_vvv, MO_16, do_vsubwod_u) ++TRANS(vsubwod_d_wu, LSX, gvec_vvv, MO_32, do_vsubwod_u) ++TRANS(vsubwod_q_du, LSX, gvec_vvv, MO_64, do_vsubwod_u) ++TRANS(xvsubwod_h_bu, LASX, gvec_xxx, MO_8, do_vsubwod_u) ++TRANS(xvsubwod_w_hu, LASX, gvec_xxx, MO_16, do_vsubwod_u) ++TRANS(xvsubwod_d_wu, LASX, gvec_xxx, MO_32, do_vsubwod_u) ++TRANS(xvsubwod_q_du, LASX, gvec_xxx, MO_64, do_vsubwod_u) ++ ++static void gen_vaddwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, t3; ++ ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ t3 = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, halfbits)); ++ ++ /* Zero-extend the even elements from a */ ++ tcg_gen_and_vec(vece, t1, a, t3); ++ ++ /* Sign-extend the even elements from b */ ++ tcg_gen_shli_vec(vece, t2, b, halfbits); ++ tcg_gen_sari_vec(vece, t2, t2, halfbits); ++ ++ tcg_gen_add_vec(vece, t, t1, t2); ++} ++ ++static void gen_vaddwev_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_ext16u_i32(t1, a); ++ tcg_gen_ext16s_i32(t2, b); ++ tcg_gen_add_i32(t, t1, t2); ++} ++ ++static void gen_vaddwev_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_ext32u_i64(t1, a); ++ tcg_gen_ext32s_i64(t2, b); ++ tcg_gen_add_i64(t, t1, t2); ++} ++ ++static void do_vaddwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shli_vec, INDEX_op_sari_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vaddwev_u_s, ++ .fno = gen_helper_vaddwev_h_bu_b, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vaddwev_w_hu_h, ++ .fniv = gen_vaddwev_u_s, ++ .fno = gen_helper_vaddwev_w_hu_h, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vaddwev_d_wu_w, ++ .fniv = gen_vaddwev_u_s, ++ .fno = gen_helper_vaddwev_d_wu_w, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ { ++ .fno = gen_helper_vaddwev_q_du_d, ++ .vece = MO_128 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vaddwev_h_bu_b, LSX, gvec_vvv, MO_8, do_vaddwev_u_s) ++TRANS(vaddwev_w_hu_h, LSX, gvec_vvv, MO_16, do_vaddwev_u_s) ++TRANS(vaddwev_d_wu_w, LSX, gvec_vvv, MO_32, do_vaddwev_u_s) ++TRANS(vaddwev_q_du_d, LSX, gvec_vvv, MO_64, do_vaddwev_u_s) ++TRANS(xvaddwev_h_bu_b, LASX, gvec_xxx, MO_8, do_vaddwev_u_s) ++TRANS(xvaddwev_w_hu_h, LASX, gvec_xxx, MO_16, do_vaddwev_u_s) ++TRANS(xvaddwev_d_wu_w, LASX, gvec_xxx, MO_32, do_vaddwev_u_s) ++TRANS(xvaddwev_q_du_d, LASX, gvec_xxx, MO_64, do_vaddwev_u_s) ++ ++static void gen_vaddwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ ++ /* Zero-extend the odd elements from a */ ++ tcg_gen_shri_vec(vece, t1, a, halfbits); ++ /* Sign-extend the odd elements from b */ ++ tcg_gen_sari_vec(vece, t2, b, halfbits); ++ ++ tcg_gen_add_vec(vece, t, t1, t2); ++} ++ ++static void gen_vaddwod_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_shri_i32(t1, a, 16); ++ tcg_gen_sari_i32(t2, b, 16); ++ tcg_gen_add_i32(t, t1, t2); ++} ++ ++static void gen_vaddwod_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_shri_i64(t1, a, 32); ++ tcg_gen_sari_i64(t2, b, 32); ++ tcg_gen_add_i64(t, t1, t2); ++} ++ ++static void do_vaddwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shri_vec, INDEX_op_sari_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vaddwod_u_s, ++ .fno = gen_helper_vaddwod_h_bu_b, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vaddwod_w_hu_h, ++ .fniv = gen_vaddwod_u_s, ++ .fno = gen_helper_vaddwod_w_hu_h, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vaddwod_d_wu_w, ++ .fniv = gen_vaddwod_u_s, ++ .fno = gen_helper_vaddwod_d_wu_w, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ { ++ .fno = gen_helper_vaddwod_q_du_d, ++ .vece = MO_128 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vaddwod_h_bu_b, LSX, gvec_vvv, MO_8, do_vaddwod_u_s) ++TRANS(vaddwod_w_hu_h, LSX, gvec_vvv, MO_16, do_vaddwod_u_s) ++TRANS(vaddwod_d_wu_w, LSX, gvec_vvv, MO_32, do_vaddwod_u_s) ++TRANS(vaddwod_q_du_d, LSX, gvec_vvv, MO_64, do_vaddwod_u_s) ++TRANS(xvaddwod_h_bu_b, LSX, gvec_xxx, MO_8, do_vaddwod_u_s) ++TRANS(xvaddwod_w_hu_h, LSX, gvec_xxx, MO_16, do_vaddwod_u_s) ++TRANS(xvaddwod_d_wu_w, LSX, gvec_xxx, MO_32, do_vaddwod_u_s) ++TRANS(xvaddwod_q_du_d, LSX, gvec_xxx, MO_64, do_vaddwod_u_s) ++ ++static void do_vavg(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, ++ void (*gen_shr_vec)(unsigned, TCGv_vec, ++ TCGv_vec, int64_t), ++ void (*gen_round_vec)(unsigned, TCGv_vec, ++ TCGv_vec, TCGv_vec)) ++{ ++ TCGv_vec tmp = tcg_temp_new_vec_matching(t); ++ gen_round_vec(vece, tmp, a, b); ++ tcg_gen_and_vec(vece, tmp, tmp, tcg_constant_vec_matching(t, vece, 1)); ++ gen_shr_vec(vece, a, a, 1); ++ gen_shr_vec(vece, b, b, 1); ++ tcg_gen_add_vec(vece, t, a, b); ++ tcg_gen_add_vec(vece, t, t, tmp); ++} ++ ++static void gen_vavg_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ do_vavg(vece, t, a, b, tcg_gen_sari_vec, tcg_gen_and_vec); ++} ++ ++static void gen_vavg_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ do_vavg(vece, t, a, b, tcg_gen_shri_vec, tcg_gen_and_vec); ++} ++ ++static void gen_vavgr_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ do_vavg(vece, t, a, b, tcg_gen_sari_vec, tcg_gen_or_vec); ++} ++ ++static void gen_vavgr_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ do_vavg(vece, t, a, b, tcg_gen_shri_vec, tcg_gen_or_vec); ++} ++ ++static void do_vavg_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_sari_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vavg_s, ++ .fno = gen_helper_vavg_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vavg_s, ++ .fno = gen_helper_vavg_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vavg_s, ++ .fno = gen_helper_vavg_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vavg_s, ++ .fno = gen_helper_vavg_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++static void do_vavg_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shri_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vavg_u, ++ .fno = gen_helper_vavg_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vavg_u, ++ .fno = gen_helper_vavg_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vavg_u, ++ .fno = gen_helper_vavg_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vavg_u, ++ .fno = gen_helper_vavg_du, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vavg_b, LSX, gvec_vvv, MO_8, do_vavg_s) ++TRANS(vavg_h, LSX, gvec_vvv, MO_16, do_vavg_s) ++TRANS(vavg_w, LSX, gvec_vvv, MO_32, do_vavg_s) ++TRANS(vavg_d, LSX, gvec_vvv, MO_64, do_vavg_s) ++TRANS(vavg_bu, LSX, gvec_vvv, MO_8, do_vavg_u) ++TRANS(vavg_hu, LSX, gvec_vvv, MO_16, do_vavg_u) ++TRANS(vavg_wu, LSX, gvec_vvv, MO_32, do_vavg_u) ++TRANS(vavg_du, LSX, gvec_vvv, MO_64, do_vavg_u) ++TRANS(xvavg_b, LASX, gvec_xxx, MO_8, do_vavg_s) ++TRANS(xvavg_h, LASX, gvec_xxx, MO_16, do_vavg_s) ++TRANS(xvavg_w, LASX, gvec_xxx, MO_32, do_vavg_s) ++TRANS(xvavg_d, LASX, gvec_xxx, MO_64, do_vavg_s) ++TRANS(xvavg_bu, LASX, gvec_xxx, MO_8, do_vavg_u) ++TRANS(xvavg_hu, LASX, gvec_xxx, MO_16, do_vavg_u) ++TRANS(xvavg_wu, LASX, gvec_xxx, MO_32, do_vavg_u) ++TRANS(xvavg_du, LASX, gvec_xxx, MO_64, do_vavg_u) ++ ++static void do_vavgr_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_sari_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vavgr_s, ++ .fno = gen_helper_vavgr_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vavgr_s, ++ .fno = gen_helper_vavgr_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vavgr_s, ++ .fno = gen_helper_vavgr_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vavgr_s, ++ .fno = gen_helper_vavgr_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++static void do_vavgr_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shri_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vavgr_u, ++ .fno = gen_helper_vavgr_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vavgr_u, ++ .fno = gen_helper_vavgr_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vavgr_u, ++ .fno = gen_helper_vavgr_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vavgr_u, ++ .fno = gen_helper_vavgr_du, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vavgr_b, LSX, gvec_vvv, MO_8, do_vavgr_s) ++TRANS(vavgr_h, LSX, gvec_vvv, MO_16, do_vavgr_s) ++TRANS(vavgr_w, LSX, gvec_vvv, MO_32, do_vavgr_s) ++TRANS(vavgr_d, LSX, gvec_vvv, MO_64, do_vavgr_s) ++TRANS(vavgr_bu, LSX, gvec_vvv, MO_8, do_vavgr_u) ++TRANS(vavgr_hu, LSX, gvec_vvv, MO_16, do_vavgr_u) ++TRANS(vavgr_wu, LSX, gvec_vvv, MO_32, do_vavgr_u) ++TRANS(vavgr_du, LSX, gvec_vvv, MO_64, do_vavgr_u) ++TRANS(xvavgr_b, LASX, gvec_xxx, MO_8, do_vavgr_s) ++TRANS(xvavgr_h, LASX, gvec_xxx, MO_16, do_vavgr_s) ++TRANS(xvavgr_w, LASX, gvec_xxx, MO_32, do_vavgr_s) ++TRANS(xvavgr_d, LASX, gvec_xxx, MO_64, do_vavgr_s) ++TRANS(xvavgr_bu, LASX, gvec_xxx, MO_8, do_vavgr_u) ++TRANS(xvavgr_hu, LASX, gvec_xxx, MO_16, do_vavgr_u) ++TRANS(xvavgr_wu, LASX, gvec_xxx, MO_32, do_vavgr_u) ++TRANS(xvavgr_du, LASX, gvec_xxx, MO_64, do_vavgr_u) ++ ++static void gen_vabsd_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ tcg_gen_smax_vec(vece, t, a, b); ++ tcg_gen_smin_vec(vece, a, a, b); ++ tcg_gen_sub_vec(vece, t, t, a); ++} ++ ++static void do_vabsd_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_smax_vec, INDEX_op_smin_vec, INDEX_op_sub_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vabsd_s, ++ .fno = gen_helper_vabsd_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vabsd_s, ++ .fno = gen_helper_vabsd_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vabsd_s, ++ .fno = gen_helper_vabsd_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vabsd_s, ++ .fno = gen_helper_vabsd_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++static void gen_vabsd_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ tcg_gen_umax_vec(vece, t, a, b); ++ tcg_gen_umin_vec(vece, a, a, b); ++ tcg_gen_sub_vec(vece, t, t, a); ++} ++ ++static void do_vabsd_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_umax_vec, INDEX_op_umin_vec, INDEX_op_sub_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vabsd_u, ++ .fno = gen_helper_vabsd_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vabsd_u, ++ .fno = gen_helper_vabsd_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vabsd_u, ++ .fno = gen_helper_vabsd_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vabsd_u, ++ .fno = gen_helper_vabsd_du, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vabsd_b, LSX, gvec_vvv, MO_8, do_vabsd_s) ++TRANS(vabsd_h, LSX, gvec_vvv, MO_16, do_vabsd_s) ++TRANS(vabsd_w, LSX, gvec_vvv, MO_32, do_vabsd_s) ++TRANS(vabsd_d, LSX, gvec_vvv, MO_64, do_vabsd_s) ++TRANS(vabsd_bu, LSX, gvec_vvv, MO_8, do_vabsd_u) ++TRANS(vabsd_hu, LSX, gvec_vvv, MO_16, do_vabsd_u) ++TRANS(vabsd_wu, LSX, gvec_vvv, MO_32, do_vabsd_u) ++TRANS(vabsd_du, LSX, gvec_vvv, MO_64, do_vabsd_u) ++TRANS(xvabsd_b, LASX, gvec_xxx, MO_8, do_vabsd_s) ++TRANS(xvabsd_h, LASX, gvec_xxx, MO_16, do_vabsd_s) ++TRANS(xvabsd_w, LASX, gvec_xxx, MO_32, do_vabsd_s) ++TRANS(xvabsd_d, LASX, gvec_xxx, MO_64, do_vabsd_s) ++TRANS(xvabsd_bu, LASX, gvec_xxx, MO_8, do_vabsd_u) ++TRANS(xvabsd_hu, LASX, gvec_xxx, MO_16, do_vabsd_u) ++TRANS(xvabsd_wu, LASX, gvec_xxx, MO_32, do_vabsd_u) ++TRANS(xvabsd_du, LASX, gvec_xxx, MO_64, do_vabsd_u) ++ ++static void gen_vadda(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ ++ tcg_gen_abs_vec(vece, t1, a); ++ tcg_gen_abs_vec(vece, t2, b); ++ tcg_gen_add_vec(vece, t, t1, t2); ++} ++ ++static void do_vadda(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_abs_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vadda, ++ .fno = gen_helper_vadda_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vadda, ++ .fno = gen_helper_vadda_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vadda, ++ .fno = gen_helper_vadda_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vadda, ++ .fno = gen_helper_vadda_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vadda_b, LSX, gvec_vvv, MO_8, do_vadda) ++TRANS(vadda_h, LSX, gvec_vvv, MO_16, do_vadda) ++TRANS(vadda_w, LSX, gvec_vvv, MO_32, do_vadda) ++TRANS(vadda_d, LSX, gvec_vvv, MO_64, do_vadda) ++TRANS(xvadda_b, LASX, gvec_xxx, MO_8, do_vadda) ++TRANS(xvadda_h, LASX, gvec_xxx, MO_16, do_vadda) ++TRANS(xvadda_w, LASX, gvec_xxx, MO_32, do_vadda) ++TRANS(xvadda_d, LASX, gvec_xxx, MO_64, do_vadda) ++ ++TRANS(vmax_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_smax) ++TRANS(vmax_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_smax) ++TRANS(vmax_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_smax) ++TRANS(vmax_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_smax) ++TRANS(vmax_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_umax) ++TRANS(vmax_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_umax) ++TRANS(vmax_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_umax) ++TRANS(vmax_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_umax) ++TRANS(xvmax_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_smax) ++TRANS(xvmax_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_smax) ++TRANS(xvmax_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_smax) ++TRANS(xvmax_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_smax) ++TRANS(xvmax_bu, LASX, gvec_xxx, MO_8, tcg_gen_gvec_umax) ++TRANS(xvmax_hu, LASX, gvec_xxx, MO_16, tcg_gen_gvec_umax) ++TRANS(xvmax_wu, LASX, gvec_xxx, MO_32, tcg_gen_gvec_umax) ++TRANS(xvmax_du, LASX, gvec_xxx, MO_64, tcg_gen_gvec_umax) ++ ++TRANS(vmin_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_smin) ++TRANS(vmin_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_smin) ++TRANS(vmin_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_smin) ++TRANS(vmin_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_smin) ++TRANS(vmin_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_umin) ++TRANS(vmin_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_umin) ++TRANS(vmin_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_umin) ++TRANS(vmin_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_umin) ++TRANS(xvmin_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_smin) ++TRANS(xvmin_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_smin) ++TRANS(xvmin_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_smin) ++TRANS(xvmin_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_smin) ++TRANS(xvmin_bu, LASX, gvec_xxx, MO_8, tcg_gen_gvec_umin) ++TRANS(xvmin_hu, LASX, gvec_xxx, MO_16, tcg_gen_gvec_umin) ++TRANS(xvmin_wu, LASX, gvec_xxx, MO_32, tcg_gen_gvec_umin) ++TRANS(xvmin_du, LASX, gvec_xxx, MO_64, tcg_gen_gvec_umin) ++ ++static void gen_vmini_s(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) ++{ ++ tcg_gen_smin_vec(vece, t, a, tcg_constant_vec_matching(t, vece, imm)); ++} ++ ++static void gen_vmini_u(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) ++{ ++ tcg_gen_umin_vec(vece, t, a, tcg_constant_vec_matching(t, vece, imm)); ++} ++ ++static void gen_vmaxi_s(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) ++{ ++ tcg_gen_smax_vec(vece, t, a, tcg_constant_vec_matching(t, vece, imm)); ++} ++ ++static void gen_vmaxi_u(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) ++{ ++ tcg_gen_umax_vec(vece, t, a, tcg_constant_vec_matching(t, vece, imm)); ++} ++ ++static void do_vmini_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ int64_t imm, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_smin_vec, 0 ++ }; ++ static const GVecGen2i op[4] = { ++ { ++ .fniv = gen_vmini_s, ++ .fnoi = gen_helper_vmini_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vmini_s, ++ .fnoi = gen_helper_vmini_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vmini_s, ++ .fnoi = gen_helper_vmini_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vmini_s, ++ .fnoi = gen_helper_vmini_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); ++} ++ ++static void do_vmini_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ int64_t imm, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_umin_vec, 0 ++ }; ++ static const GVecGen2i op[4] = { ++ { ++ .fniv = gen_vmini_u, ++ .fnoi = gen_helper_vmini_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vmini_u, ++ .fnoi = gen_helper_vmini_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vmini_u, ++ .fnoi = gen_helper_vmini_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vmini_u, ++ .fnoi = gen_helper_vmini_du, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); ++} ++ ++TRANS(vmini_b, LSX, gvec_vv_i, MO_8, do_vmini_s) ++TRANS(vmini_h, LSX, gvec_vv_i, MO_16, do_vmini_s) ++TRANS(vmini_w, LSX, gvec_vv_i, MO_32, do_vmini_s) ++TRANS(vmini_d, LSX, gvec_vv_i, MO_64, do_vmini_s) ++TRANS(vmini_bu, LSX, gvec_vv_i, MO_8, do_vmini_u) ++TRANS(vmini_hu, LSX, gvec_vv_i, MO_16, do_vmini_u) ++TRANS(vmini_wu, LSX, gvec_vv_i, MO_32, do_vmini_u) ++TRANS(vmini_du, LSX, gvec_vv_i, MO_64, do_vmini_u) ++TRANS(xvmini_b, LASX, gvec_xx_i, MO_8, do_vmini_s) ++TRANS(xvmini_h, LASX, gvec_xx_i, MO_16, do_vmini_s) ++TRANS(xvmini_w, LASX, gvec_xx_i, MO_32, do_vmini_s) ++TRANS(xvmini_d, LASX, gvec_xx_i, MO_64, do_vmini_s) ++TRANS(xvmini_bu, LASX, gvec_xx_i, MO_8, do_vmini_u) ++TRANS(xvmini_hu, LASX, gvec_xx_i, MO_16, do_vmini_u) ++TRANS(xvmini_wu, LASX, gvec_xx_i, MO_32, do_vmini_u) ++TRANS(xvmini_du, LASX, gvec_xx_i, MO_64, do_vmini_u) ++ ++static void do_vmaxi_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ int64_t imm, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_smax_vec, 0 ++ }; ++ static const GVecGen2i op[4] = { ++ { ++ .fniv = gen_vmaxi_s, ++ .fnoi = gen_helper_vmaxi_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vmaxi_s, ++ .fnoi = gen_helper_vmaxi_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vmaxi_s, ++ .fnoi = gen_helper_vmaxi_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vmaxi_s, ++ .fnoi = gen_helper_vmaxi_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); ++} ++ ++static void do_vmaxi_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ int64_t imm, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_umax_vec, 0 ++ }; ++ static const GVecGen2i op[4] = { ++ { ++ .fniv = gen_vmaxi_u, ++ .fnoi = gen_helper_vmaxi_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vmaxi_u, ++ .fnoi = gen_helper_vmaxi_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vmaxi_u, ++ .fnoi = gen_helper_vmaxi_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vmaxi_u, ++ .fnoi = gen_helper_vmaxi_du, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); ++} ++ ++TRANS(vmaxi_b, LSX, gvec_vv_i, MO_8, do_vmaxi_s) ++TRANS(vmaxi_h, LSX, gvec_vv_i, MO_16, do_vmaxi_s) ++TRANS(vmaxi_w, LSX, gvec_vv_i, MO_32, do_vmaxi_s) ++TRANS(vmaxi_d, LSX, gvec_vv_i, MO_64, do_vmaxi_s) ++TRANS(vmaxi_bu, LSX, gvec_vv_i, MO_8, do_vmaxi_u) ++TRANS(vmaxi_hu, LSX, gvec_vv_i, MO_16, do_vmaxi_u) ++TRANS(vmaxi_wu, LSX, gvec_vv_i, MO_32, do_vmaxi_u) ++TRANS(vmaxi_du, LSX, gvec_vv_i, MO_64, do_vmaxi_u) ++TRANS(xvmaxi_b, LASX, gvec_xx_i, MO_8, do_vmaxi_s) ++TRANS(xvmaxi_h, LASX, gvec_xx_i, MO_16, do_vmaxi_s) ++TRANS(xvmaxi_w, LASX, gvec_xx_i, MO_32, do_vmaxi_s) ++TRANS(xvmaxi_d, LASX, gvec_xx_i, MO_64, do_vmaxi_s) ++TRANS(xvmaxi_bu, LASX, gvec_xx_i, MO_8, do_vmaxi_u) ++TRANS(xvmaxi_hu, LASX, gvec_xx_i, MO_16, do_vmaxi_u) ++TRANS(xvmaxi_wu, LASX, gvec_xx_i, MO_32, do_vmaxi_u) ++TRANS(xvmaxi_du, LASX, gvec_xx_i, MO_64, do_vmaxi_u) ++ ++TRANS(vmul_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_mul) ++TRANS(vmul_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_mul) ++TRANS(vmul_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_mul) ++TRANS(vmul_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_mul) ++TRANS(xvmul_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_mul) ++TRANS(xvmul_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_mul) ++TRANS(xvmul_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_mul) ++TRANS(xvmul_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_mul) ++ ++static void gen_vmuh_w(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 discard = tcg_temp_new_i32(); ++ tcg_gen_muls2_i32(discard, t, a, b); ++} ++ ++static void gen_vmuh_d(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 discard = tcg_temp_new_i64(); ++ tcg_gen_muls2_i64(discard, t, a, b); ++} ++ ++static void do_vmuh_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const GVecGen3 op[4] = { ++ { ++ .fno = gen_helper_vmuh_b, ++ .vece = MO_8 ++ }, ++ { ++ .fno = gen_helper_vmuh_h, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmuh_w, ++ .fno = gen_helper_vmuh_w, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmuh_d, ++ .fno = gen_helper_vmuh_d, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmuh_b, LSX, gvec_vvv, MO_8, do_vmuh_s) ++TRANS(vmuh_h, LSX, gvec_vvv, MO_16, do_vmuh_s) ++TRANS(vmuh_w, LSX, gvec_vvv, MO_32, do_vmuh_s) ++TRANS(vmuh_d, LSX, gvec_vvv, MO_64, do_vmuh_s) ++TRANS(xvmuh_b, LASX, gvec_xxx, MO_8, do_vmuh_s) ++TRANS(xvmuh_h, LASX, gvec_xxx, MO_16, do_vmuh_s) ++TRANS(xvmuh_w, LASX, gvec_xxx, MO_32, do_vmuh_s) ++TRANS(xvmuh_d, LASX, gvec_xxx, MO_64, do_vmuh_s) ++ ++static void gen_vmuh_wu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 discard = tcg_temp_new_i32(); ++ tcg_gen_mulu2_i32(discard, t, a, b); ++} ++ ++static void gen_vmuh_du(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 discard = tcg_temp_new_i64(); ++ tcg_gen_mulu2_i64(discard, t, a, b); ++} ++ ++static void do_vmuh_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const GVecGen3 op[4] = { ++ { ++ .fno = gen_helper_vmuh_bu, ++ .vece = MO_8 ++ }, ++ { ++ .fno = gen_helper_vmuh_hu, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmuh_wu, ++ .fno = gen_helper_vmuh_wu, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmuh_du, ++ .fno = gen_helper_vmuh_du, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmuh_bu, LSX, gvec_vvv, MO_8, do_vmuh_u) ++TRANS(vmuh_hu, LSX, gvec_vvv, MO_16, do_vmuh_u) ++TRANS(vmuh_wu, LSX, gvec_vvv, MO_32, do_vmuh_u) ++TRANS(vmuh_du, LSX, gvec_vvv, MO_64, do_vmuh_u) ++TRANS(xvmuh_bu, LASX, gvec_xxx, MO_8, do_vmuh_u) ++TRANS(xvmuh_hu, LASX, gvec_xxx, MO_16, do_vmuh_u) ++TRANS(xvmuh_wu, LASX, gvec_xxx, MO_32, do_vmuh_u) ++TRANS(xvmuh_du, LASX, gvec_xxx, MO_64, do_vmuh_u) ++ ++static void gen_vmulwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ tcg_gen_shli_vec(vece, t1, a, halfbits); ++ tcg_gen_sari_vec(vece, t1, t1, halfbits); ++ tcg_gen_shli_vec(vece, t2, b, halfbits); ++ tcg_gen_sari_vec(vece, t2, t2, halfbits); ++ tcg_gen_mul_vec(vece, t, t1, t2); ++} ++ ++static void gen_vmulwev_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_ext16s_i32(t1, a); ++ tcg_gen_ext16s_i32(t2, b); ++ tcg_gen_mul_i32(t, t1, t2); ++} ++ ++static void gen_vmulwev_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_ext32s_i64(t1, a); ++ tcg_gen_ext32s_i64(t2, b); ++ tcg_gen_mul_i64(t, t1, t2); ++} ++ ++static void do_vmulwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shli_vec, INDEX_op_sari_vec, INDEX_op_mul_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmulwev_s, ++ .fno = gen_helper_vmulwev_h_b, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmulwev_w_h, ++ .fniv = gen_vmulwev_s, ++ .fno = gen_helper_vmulwev_w_h, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmulwev_d_w, ++ .fniv = gen_vmulwev_s, ++ .fno = gen_helper_vmulwev_d_w, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmulwev_h_b, LSX, gvec_vvv, MO_8, do_vmulwev_s) ++TRANS(vmulwev_w_h, LSX, gvec_vvv, MO_16, do_vmulwev_s) ++TRANS(vmulwev_d_w, LSX, gvec_vvv, MO_32, do_vmulwev_s) ++TRANS(xvmulwev_h_b, LASX, gvec_xxx, MO_8, do_vmulwev_s) ++TRANS(xvmulwev_w_h, LASX, gvec_xxx, MO_16, do_vmulwev_s) ++TRANS(xvmulwev_d_w, LASX, gvec_xxx, MO_32, do_vmulwev_s) ++ ++static void tcg_gen_mulus2_i64(TCGv_i64 rl, TCGv_i64 rh, ++ TCGv_i64 arg1, TCGv_i64 arg2) ++{ ++ tcg_gen_mulsu2_i64(rl, rh, arg2, arg1); ++} ++ ++static bool gen_vmul_q_vl(DisasContext *ctx, ++ arg_vvv *a, uint32_t oprsz, int idx1, int idx2, ++ void (*func)(TCGv_i64, TCGv_i64, ++ TCGv_i64, TCGv_i64)) ++{ ++ TCGv_i64 rh, rl, arg1, arg2; ++ int i; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ rh = tcg_temp_new_i64(); ++ rl = tcg_temp_new_i64(); ++ arg1 = tcg_temp_new_i64(); ++ arg2 = tcg_temp_new_i64(); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ get_vreg64(arg1, a->vj, 2 * i + idx1); ++ get_vreg64(arg2, a->vk, 2 * i + idx2); ++ ++ func(rl, rh, arg1, arg2); ++ ++ set_vreg64(rh, a->vd, 2 * i + 1); ++ set_vreg64(rl, a->vd, 2 * i); ++ } ++ ++ return true; ++} ++ ++static bool gen_vmul_q(DisasContext *ctx, arg_vvv *a, int idx1, int idx2, ++ void (*func)(TCGv_i64, TCGv_i64, ++ TCGv_i64, TCGv_i64)) ++{ ++ return gen_vmul_q_vl(ctx, a, 16, idx1, idx2, func); ++} ++ ++static bool gen_xvmul_q(DisasContext *ctx, arg_vvv *a, int idx1, int idx2, ++ void (*func)(TCGv_i64, TCGv_i64, ++ TCGv_i64, TCGv_i64)) ++{ ++ return gen_vmul_q_vl(ctx, a, 32, idx1, idx2, func); ++} ++ ++TRANS(vmulwev_q_d, LSX, gen_vmul_q, 0, 0, tcg_gen_muls2_i64) ++TRANS(vmulwod_q_d, LSX, gen_vmul_q, 1, 1, tcg_gen_muls2_i64) ++TRANS(vmulwev_q_du, LSX, gen_vmul_q, 0, 0, tcg_gen_mulu2_i64) ++TRANS(vmulwod_q_du, LSX, gen_vmul_q, 1, 1, tcg_gen_mulu2_i64) ++TRANS(vmulwev_q_du_d, LSX, gen_vmul_q, 0, 0, tcg_gen_mulus2_i64) ++TRANS(vmulwod_q_du_d, LSX, gen_vmul_q, 1, 1, tcg_gen_mulus2_i64) ++TRANS(xvmulwev_q_d, LASX, gen_xvmul_q, 0, 0, tcg_gen_muls2_i64) ++TRANS(xvmulwod_q_d, LASX, gen_xvmul_q, 1, 1, tcg_gen_muls2_i64) ++TRANS(xvmulwev_q_du, LASX, gen_xvmul_q, 0, 0, tcg_gen_mulu2_i64) ++TRANS(xvmulwod_q_du, LASX, gen_xvmul_q, 1, 1, tcg_gen_mulu2_i64) ++TRANS(xvmulwev_q_du_d, LASX, gen_xvmul_q, 0, 0, tcg_gen_mulus2_i64) ++TRANS(xvmulwod_q_du_d, LASX, gen_xvmul_q, 1, 1, tcg_gen_mulus2_i64) ++ ++static void gen_vmulwod_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ tcg_gen_sari_vec(vece, t1, a, halfbits); ++ tcg_gen_sari_vec(vece, t2, b, halfbits); ++ tcg_gen_mul_vec(vece, t, t1, t2); ++} ++ ++static void gen_vmulwod_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_sari_i32(t1, a, 16); ++ tcg_gen_sari_i32(t2, b, 16); ++ tcg_gen_mul_i32(t, t1, t2); ++} ++ ++static void gen_vmulwod_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_sari_i64(t1, a, 32); ++ tcg_gen_sari_i64(t2, b, 32); ++ tcg_gen_mul_i64(t, t1, t2); ++} ++ ++static void do_vmulwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_sari_vec, INDEX_op_mul_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmulwod_s, ++ .fno = gen_helper_vmulwod_h_b, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmulwod_w_h, ++ .fniv = gen_vmulwod_s, ++ .fno = gen_helper_vmulwod_w_h, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmulwod_d_w, ++ .fniv = gen_vmulwod_s, ++ .fno = gen_helper_vmulwod_d_w, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmulwod_h_b, LSX, gvec_vvv, MO_8, do_vmulwod_s) ++TRANS(vmulwod_w_h, LSX, gvec_vvv, MO_16, do_vmulwod_s) ++TRANS(vmulwod_d_w, LSX, gvec_vvv, MO_32, do_vmulwod_s) ++TRANS(xvmulwod_h_b, LASX, gvec_xxx, MO_8, do_vmulwod_s) ++TRANS(xvmulwod_w_h, LASX, gvec_xxx, MO_16, do_vmulwod_s) ++TRANS(xvmulwod_d_w, LASX, gvec_xxx, MO_32, do_vmulwod_s) ++ ++static void gen_vmulwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, mask; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ mask = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); ++ tcg_gen_and_vec(vece, t1, a, mask); ++ tcg_gen_and_vec(vece, t2, b, mask); ++ tcg_gen_mul_vec(vece, t, t1, t2); ++} ++ ++static void gen_vmulwev_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_ext16u_i32(t1, a); ++ tcg_gen_ext16u_i32(t2, b); ++ tcg_gen_mul_i32(t, t1, t2); ++} ++ ++static void gen_vmulwev_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_ext32u_i64(t1, a); ++ tcg_gen_ext32u_i64(t2, b); ++ tcg_gen_mul_i64(t, t1, t2); ++} ++ ++static void do_vmulwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_mul_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmulwev_u, ++ .fno = gen_helper_vmulwev_h_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmulwev_w_hu, ++ .fniv = gen_vmulwev_u, ++ .fno = gen_helper_vmulwev_w_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmulwev_d_wu, ++ .fniv = gen_vmulwev_u, ++ .fno = gen_helper_vmulwev_d_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmulwev_h_bu, LSX, gvec_vvv, MO_8, do_vmulwev_u) ++TRANS(vmulwev_w_hu, LSX, gvec_vvv, MO_16, do_vmulwev_u) ++TRANS(vmulwev_d_wu, LSX, gvec_vvv, MO_32, do_vmulwev_u) ++TRANS(xvmulwev_h_bu, LASX, gvec_xxx, MO_8, do_vmulwev_u) ++TRANS(xvmulwev_w_hu, LASX, gvec_xxx, MO_16, do_vmulwev_u) ++TRANS(xvmulwev_d_wu, LASX, gvec_xxx, MO_32, do_vmulwev_u) ++ ++static void gen_vmulwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ tcg_gen_shri_vec(vece, t1, a, halfbits); ++ tcg_gen_shri_vec(vece, t2, b, halfbits); ++ tcg_gen_mul_vec(vece, t, t1, t2); ++} ++ ++static void gen_vmulwod_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_shri_i32(t1, a, 16); ++ tcg_gen_shri_i32(t2, b, 16); ++ tcg_gen_mul_i32(t, t1, t2); ++} ++ ++static void gen_vmulwod_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_shri_i64(t1, a, 32); ++ tcg_gen_shri_i64(t2, b, 32); ++ tcg_gen_mul_i64(t, t1, t2); ++} ++ ++static void do_vmulwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shri_vec, INDEX_op_mul_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmulwod_u, ++ .fno = gen_helper_vmulwod_h_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmulwod_w_hu, ++ .fniv = gen_vmulwod_u, ++ .fno = gen_helper_vmulwod_w_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmulwod_d_wu, ++ .fniv = gen_vmulwod_u, ++ .fno = gen_helper_vmulwod_d_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmulwod_h_bu, LSX, gvec_vvv, MO_8, do_vmulwod_u) ++TRANS(vmulwod_w_hu, LSX, gvec_vvv, MO_16, do_vmulwod_u) ++TRANS(vmulwod_d_wu, LSX, gvec_vvv, MO_32, do_vmulwod_u) ++TRANS(xvmulwod_h_bu, LASX, gvec_xxx, MO_8, do_vmulwod_u) ++TRANS(xvmulwod_w_hu, LASX, gvec_xxx, MO_16, do_vmulwod_u) ++TRANS(xvmulwod_d_wu, LASX, gvec_xxx, MO_32, do_vmulwod_u) ++ ++static void gen_vmulwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, mask; ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ mask = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); ++ tcg_gen_and_vec(vece, t1, a, mask); ++ tcg_gen_shli_vec(vece, t2, b, halfbits); ++ tcg_gen_sari_vec(vece, t2, t2, halfbits); ++ tcg_gen_mul_vec(vece, t, t1, t2); ++} ++ ++static void gen_vmulwev_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_ext16u_i32(t1, a); ++ tcg_gen_ext16s_i32(t2, b); ++ tcg_gen_mul_i32(t, t1, t2); ++} ++ ++static void gen_vmulwev_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_ext32u_i64(t1, a); ++ tcg_gen_ext32s_i64(t2, b); ++ tcg_gen_mul_i64(t, t1, t2); ++} ++ ++static void do_vmulwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shli_vec, INDEX_op_sari_vec, INDEX_op_mul_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmulwev_u_s, ++ .fno = gen_helper_vmulwev_h_bu_b, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmulwev_w_hu_h, ++ .fniv = gen_vmulwev_u_s, ++ .fno = gen_helper_vmulwev_w_hu_h, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmulwev_d_wu_w, ++ .fniv = gen_vmulwev_u_s, ++ .fno = gen_helper_vmulwev_d_wu_w, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmulwev_h_bu_b, LSX, gvec_vvv, MO_8, do_vmulwev_u_s) ++TRANS(vmulwev_w_hu_h, LSX, gvec_vvv, MO_16, do_vmulwev_u_s) ++TRANS(vmulwev_d_wu_w, LSX, gvec_vvv, MO_32, do_vmulwev_u_s) ++TRANS(xvmulwev_h_bu_b, LASX, gvec_xxx, MO_8, do_vmulwev_u_s) ++TRANS(xvmulwev_w_hu_h, LASX, gvec_xxx, MO_16, do_vmulwev_u_s) ++TRANS(xvmulwev_d_wu_w, LASX, gvec_xxx, MO_32, do_vmulwev_u_s) ++ ++static void gen_vmulwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2; ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ tcg_gen_shri_vec(vece, t1, a, halfbits); ++ tcg_gen_sari_vec(vece, t2, b, halfbits); ++ tcg_gen_mul_vec(vece, t, t1, t2); ++} ++ ++static void gen_vmulwod_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1, t2; ++ ++ t1 = tcg_temp_new_i32(); ++ t2 = tcg_temp_new_i32(); ++ tcg_gen_shri_i32(t1, a, 16); ++ tcg_gen_sari_i32(t2, b, 16); ++ tcg_gen_mul_i32(t, t1, t2); ++} ++static void gen_vmulwod_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1, t2; ++ ++ t1 = tcg_temp_new_i64(); ++ t2 = tcg_temp_new_i64(); ++ tcg_gen_shri_i64(t1, a, 32); ++ tcg_gen_sari_i64(t2, b, 32); ++ tcg_gen_mul_i64(t, t1, t2); ++} ++ ++static void do_vmulwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shri_vec, INDEX_op_sari_vec, INDEX_op_mul_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmulwod_u_s, ++ .fno = gen_helper_vmulwod_h_bu_b, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmulwod_w_hu_h, ++ .fniv = gen_vmulwod_u_s, ++ .fno = gen_helper_vmulwod_w_hu_h, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmulwod_d_wu_w, ++ .fniv = gen_vmulwod_u_s, ++ .fno = gen_helper_vmulwod_d_wu_w, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmulwod_h_bu_b, LSX, gvec_vvv, MO_8, do_vmulwod_u_s) ++TRANS(vmulwod_w_hu_h, LSX, gvec_vvv, MO_16, do_vmulwod_u_s) ++TRANS(vmulwod_d_wu_w, LSX, gvec_vvv, MO_32, do_vmulwod_u_s) ++TRANS(xvmulwod_h_bu_b, LASX, gvec_xxx, MO_8, do_vmulwod_u_s) ++TRANS(xvmulwod_w_hu_h, LASX, gvec_xxx, MO_16, do_vmulwod_u_s) ++TRANS(xvmulwod_d_wu_w, LASX, gvec_xxx, MO_32, do_vmulwod_u_s) ++ ++static void gen_vmadd(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1; ++ ++ t1 = tcg_temp_new_vec_matching(t); ++ tcg_gen_mul_vec(vece, t1, a, b); ++ tcg_gen_add_vec(vece, t, t, t1); ++} ++ ++static void gen_vmadd_w(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1; ++ ++ t1 = tcg_temp_new_i32(); ++ tcg_gen_mul_i32(t1, a, b); ++ tcg_gen_add_i32(t, t, t1); ++} ++ ++static void gen_vmadd_d(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1; ++ ++ t1 = tcg_temp_new_i64(); ++ tcg_gen_mul_i64(t1, a, b); ++ tcg_gen_add_i64(t, t, t1); ++} ++ ++static void do_vmadd(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_mul_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vmadd, ++ .fno = gen_helper_vmadd_b, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vmadd, ++ .fno = gen_helper_vmadd_h, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmadd_w, ++ .fniv = gen_vmadd, ++ .fno = gen_helper_vmadd_w, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmadd_d, ++ .fniv = gen_vmadd, ++ .fno = gen_helper_vmadd_d, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmadd_b, LSX, gvec_vvv, MO_8, do_vmadd) ++TRANS(vmadd_h, LSX, gvec_vvv, MO_16, do_vmadd) ++TRANS(vmadd_w, LSX, gvec_vvv, MO_32, do_vmadd) ++TRANS(vmadd_d, LSX, gvec_vvv, MO_64, do_vmadd) ++TRANS(xvmadd_b, LASX, gvec_xxx, MO_8, do_vmadd) ++TRANS(xvmadd_h, LASX, gvec_xxx, MO_16, do_vmadd) ++TRANS(xvmadd_w, LASX, gvec_xxx, MO_32, do_vmadd) ++TRANS(xvmadd_d, LASX, gvec_xxx, MO_64, do_vmadd) ++ ++static void gen_vmsub(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1; ++ ++ t1 = tcg_temp_new_vec_matching(t); ++ tcg_gen_mul_vec(vece, t1, a, b); ++ tcg_gen_sub_vec(vece, t, t, t1); ++} ++ ++static void gen_vmsub_w(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1; ++ ++ t1 = tcg_temp_new_i32(); ++ tcg_gen_mul_i32(t1, a, b); ++ tcg_gen_sub_i32(t, t, t1); ++} ++ ++static void gen_vmsub_d(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1; ++ ++ t1 = tcg_temp_new_i64(); ++ tcg_gen_mul_i64(t1, a, b); ++ tcg_gen_sub_i64(t, t, t1); ++} ++ ++static void do_vmsub(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_mul_vec, INDEX_op_sub_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vmsub, ++ .fno = gen_helper_vmsub_b, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vmsub, ++ .fno = gen_helper_vmsub_h, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmsub_w, ++ .fniv = gen_vmsub, ++ .fno = gen_helper_vmsub_w, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmsub_d, ++ .fniv = gen_vmsub, ++ .fno = gen_helper_vmsub_d, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmsub_b, LSX, gvec_vvv, MO_8, do_vmsub) ++TRANS(vmsub_h, LSX, gvec_vvv, MO_16, do_vmsub) ++TRANS(vmsub_w, LSX, gvec_vvv, MO_32, do_vmsub) ++TRANS(vmsub_d, LSX, gvec_vvv, MO_64, do_vmsub) ++TRANS(xvmsub_b, LASX, gvec_xxx, MO_8, do_vmsub) ++TRANS(xvmsub_h, LASX, gvec_xxx, MO_16, do_vmsub) ++TRANS(xvmsub_w, LASX, gvec_xxx, MO_32, do_vmsub) ++TRANS(xvmsub_d, LASX, gvec_xxx, MO_64, do_vmsub) ++ ++static void gen_vmaddwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, t3; ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ t3 = tcg_temp_new_vec_matching(t); ++ tcg_gen_shli_vec(vece, t1, a, halfbits); ++ tcg_gen_sari_vec(vece, t1, t1, halfbits); ++ tcg_gen_shli_vec(vece, t2, b, halfbits); ++ tcg_gen_sari_vec(vece, t2, t2, halfbits); ++ tcg_gen_mul_vec(vece, t3, t1, t2); ++ tcg_gen_add_vec(vece, t, t, t3); ++} ++ ++static void gen_vmaddwev_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1; ++ ++ t1 = tcg_temp_new_i32(); ++ gen_vmulwev_w_h(t1, a, b); ++ tcg_gen_add_i32(t, t, t1); ++} ++ ++static void gen_vmaddwev_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1; ++ ++ t1 = tcg_temp_new_i64(); ++ gen_vmulwev_d_w(t1, a, b); ++ tcg_gen_add_i64(t, t, t1); ++} ++ ++static void do_vmaddwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shli_vec, INDEX_op_sari_vec, ++ INDEX_op_mul_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmaddwev_s, ++ .fno = gen_helper_vmaddwev_h_b, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmaddwev_w_h, ++ .fniv = gen_vmaddwev_s, ++ .fno = gen_helper_vmaddwev_w_h, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmaddwev_d_w, ++ .fniv = gen_vmaddwev_s, ++ .fno = gen_helper_vmaddwev_d_w, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmaddwev_h_b, LSX, gvec_vvv, MO_8, do_vmaddwev_s) ++TRANS(vmaddwev_w_h, LSX, gvec_vvv, MO_16, do_vmaddwev_s) ++TRANS(vmaddwev_d_w, LSX, gvec_vvv, MO_32, do_vmaddwev_s) ++TRANS(xvmaddwev_h_b, LASX, gvec_xxx, MO_8, do_vmaddwev_s) ++TRANS(xvmaddwev_w_h, LASX, gvec_xxx, MO_16, do_vmaddwev_s) ++TRANS(xvmaddwev_d_w, LASX, gvec_xxx, MO_32, do_vmaddwev_s) ++ ++static bool gen_vmadd_q_vl(DisasContext * ctx, ++ arg_vvv *a, uint32_t oprsz, int idx1, int idx2, ++ void (*func)(TCGv_i64, TCGv_i64, ++ TCGv_i64, TCGv_i64)) ++{ ++ TCGv_i64 rh, rl, arg1, arg2, th, tl; ++ int i; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ rh = tcg_temp_new_i64(); ++ rl = tcg_temp_new_i64(); ++ arg1 = tcg_temp_new_i64(); ++ arg2 = tcg_temp_new_i64(); ++ th = tcg_temp_new_i64(); ++ tl = tcg_temp_new_i64(); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ get_vreg64(arg1, a->vj, 2 * i + idx1); ++ get_vreg64(arg2, a->vk, 2 * i + idx2); ++ get_vreg64(rh, a->vd, 2 * i + 1); ++ get_vreg64(rl, a->vd, 2 * i); ++ ++ func(tl, th, arg1, arg2); ++ tcg_gen_add2_i64(rl, rh, rl, rh, tl, th); ++ ++ set_vreg64(rh, a->vd, 2 * i + 1); ++ set_vreg64(rl, a->vd, 2 * i); ++ } ++ ++ return true; ++} ++ ++static bool gen_vmadd_q(DisasContext *ctx, arg_vvv *a, int idx1, int idx2, ++ void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) ++{ ++ return gen_vmadd_q_vl(ctx, a, 16, idx1, idx2, func); ++} ++ ++static bool gen_xvmadd_q(DisasContext *ctx, arg_vvv *a, int idx1, int idx2, ++ void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) ++{ ++ return gen_vmadd_q_vl(ctx, a, 32, idx1, idx2, func); ++} ++ ++TRANS(vmaddwev_q_d, LSX, gen_vmadd_q, 0, 0, tcg_gen_muls2_i64) ++TRANS(vmaddwod_q_d, LSX, gen_vmadd_q, 1, 1, tcg_gen_muls2_i64) ++TRANS(vmaddwev_q_du, LSX, gen_vmadd_q, 0, 0, tcg_gen_mulu2_i64) ++TRANS(vmaddwod_q_du, LSX, gen_vmadd_q, 1, 1, tcg_gen_mulu2_i64) ++TRANS(vmaddwev_q_du_d, LSX, gen_vmadd_q, 0, 0, tcg_gen_mulus2_i64) ++TRANS(vmaddwod_q_du_d, LSX, gen_vmadd_q, 1, 1, tcg_gen_mulus2_i64) ++TRANS(xvmaddwev_q_d, LASX, gen_xvmadd_q, 0, 0, tcg_gen_muls2_i64) ++TRANS(xvmaddwod_q_d, LASX, gen_xvmadd_q, 1, 1, tcg_gen_muls2_i64) ++TRANS(xvmaddwev_q_du, LASX, gen_xvmadd_q, 0, 0, tcg_gen_mulu2_i64) ++TRANS(xvmaddwod_q_du, LASX, gen_xvmadd_q, 1, 1, tcg_gen_mulu2_i64) ++TRANS(xvmaddwev_q_du_d, LASX, gen_xvmadd_q, 0, 0, tcg_gen_mulus2_i64) ++TRANS(xvmaddwod_q_du_d, LASX, gen_xvmadd_q, 1, 1, tcg_gen_mulus2_i64) ++ ++static void gen_vmaddwod_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, t3; ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ t3 = tcg_temp_new_vec_matching(t); ++ tcg_gen_sari_vec(vece, t1, a, halfbits); ++ tcg_gen_sari_vec(vece, t2, b, halfbits); ++ tcg_gen_mul_vec(vece, t3, t1, t2); ++ tcg_gen_add_vec(vece, t, t, t3); ++} ++ ++static void gen_vmaddwod_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1; ++ ++ t1 = tcg_temp_new_i32(); ++ gen_vmulwod_w_h(t1, a, b); ++ tcg_gen_add_i32(t, t, t1); ++} ++ ++static void gen_vmaddwod_d_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1; ++ ++ t1 = tcg_temp_new_i64(); ++ gen_vmulwod_d_w(t1, a, b); ++ tcg_gen_add_i64(t, t, t1); ++} ++ ++static void do_vmaddwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_sari_vec, INDEX_op_mul_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmaddwod_s, ++ .fno = gen_helper_vmaddwod_h_b, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmaddwod_w_h, ++ .fniv = gen_vmaddwod_s, ++ .fno = gen_helper_vmaddwod_w_h, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmaddwod_d_w, ++ .fniv = gen_vmaddwod_s, ++ .fno = gen_helper_vmaddwod_d_w, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmaddwod_h_b, LSX, gvec_vvv, MO_8, do_vmaddwod_s) ++TRANS(vmaddwod_w_h, LSX, gvec_vvv, MO_16, do_vmaddwod_s) ++TRANS(vmaddwod_d_w, LSX, gvec_vvv, MO_32, do_vmaddwod_s) ++TRANS(xvmaddwod_h_b, LASX, gvec_xxx, MO_8, do_vmaddwod_s) ++TRANS(xvmaddwod_w_h, LASX, gvec_xxx, MO_16, do_vmaddwod_s) ++TRANS(xvmaddwod_d_w, LASX, gvec_xxx, MO_32, do_vmaddwod_s) ++ ++static void gen_vmaddwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, mask; ++ ++ t1 = tcg_temp_new_vec_matching(t); ++ t2 = tcg_temp_new_vec_matching(b); ++ mask = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); ++ tcg_gen_and_vec(vece, t1, a, mask); ++ tcg_gen_and_vec(vece, t2, b, mask); ++ tcg_gen_mul_vec(vece, t1, t1, t2); ++ tcg_gen_add_vec(vece, t, t, t1); ++} ++ ++static void gen_vmaddwev_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1; ++ ++ t1 = tcg_temp_new_i32(); ++ gen_vmulwev_w_hu(t1, a, b); ++ tcg_gen_add_i32(t, t, t1); ++} ++ ++static void gen_vmaddwev_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1; ++ ++ t1 = tcg_temp_new_i64(); ++ gen_vmulwev_d_wu(t1, a, b); ++ tcg_gen_add_i64(t, t, t1); ++} ++ ++static void do_vmaddwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_mul_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmaddwev_u, ++ .fno = gen_helper_vmaddwev_h_bu, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmaddwev_w_hu, ++ .fniv = gen_vmaddwev_u, ++ .fno = gen_helper_vmaddwev_w_hu, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmaddwev_d_wu, ++ .fniv = gen_vmaddwev_u, ++ .fno = gen_helper_vmaddwev_d_wu, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmaddwev_h_bu, LSX, gvec_vvv, MO_8, do_vmaddwev_u) ++TRANS(vmaddwev_w_hu, LSX, gvec_vvv, MO_16, do_vmaddwev_u) ++TRANS(vmaddwev_d_wu, LSX, gvec_vvv, MO_32, do_vmaddwev_u) ++TRANS(xvmaddwev_h_bu, LASX, gvec_xxx, MO_8, do_vmaddwev_u) ++TRANS(xvmaddwev_w_hu, LASX, gvec_xxx, MO_16, do_vmaddwev_u) ++TRANS(xvmaddwev_d_wu, LASX, gvec_xxx, MO_32, do_vmaddwev_u) ++ ++static void gen_vmaddwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, t3; ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ t3 = tcg_temp_new_vec_matching(t); ++ tcg_gen_shri_vec(vece, t1, a, halfbits); ++ tcg_gen_shri_vec(vece, t2, b, halfbits); ++ tcg_gen_mul_vec(vece, t3, t1, t2); ++ tcg_gen_add_vec(vece, t, t, t3); ++} ++ ++static void gen_vmaddwod_w_hu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1; ++ ++ t1 = tcg_temp_new_i32(); ++ gen_vmulwod_w_hu(t1, a, b); ++ tcg_gen_add_i32(t, t, t1); ++} ++ ++static void gen_vmaddwod_d_wu(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1; ++ ++ t1 = tcg_temp_new_i64(); ++ gen_vmulwod_d_wu(t1, a, b); ++ tcg_gen_add_i64(t, t, t1); ++} ++ ++static void do_vmaddwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shri_vec, INDEX_op_mul_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmaddwod_u, ++ .fno = gen_helper_vmaddwod_h_bu, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmaddwod_w_hu, ++ .fniv = gen_vmaddwod_u, ++ .fno = gen_helper_vmaddwod_w_hu, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmaddwod_d_wu, ++ .fniv = gen_vmaddwod_u, ++ .fno = gen_helper_vmaddwod_d_wu, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmaddwod_h_bu, LSX, gvec_vvv, MO_8, do_vmaddwod_u) ++TRANS(vmaddwod_w_hu, LSX, gvec_vvv, MO_16, do_vmaddwod_u) ++TRANS(vmaddwod_d_wu, LSX, gvec_vvv, MO_32, do_vmaddwod_u) ++TRANS(xvmaddwod_h_bu, LASX, gvec_xxx, MO_8, do_vmaddwod_u) ++TRANS(xvmaddwod_w_hu, LASX, gvec_xxx, MO_16, do_vmaddwod_u) ++TRANS(xvmaddwod_d_wu, LASX, gvec_xxx, MO_32, do_vmaddwod_u) ++ ++static void gen_vmaddwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, mask; ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ mask = tcg_constant_vec_matching(t, vece, MAKE_64BIT_MASK(0, 4 << vece)); ++ tcg_gen_and_vec(vece, t1, a, mask); ++ tcg_gen_shli_vec(vece, t2, b, halfbits); ++ tcg_gen_sari_vec(vece, t2, t2, halfbits); ++ tcg_gen_mul_vec(vece, t1, t1, t2); ++ tcg_gen_add_vec(vece, t, t, t1); ++} ++ ++static void gen_vmaddwev_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1; ++ ++ t1 = tcg_temp_new_i32(); ++ gen_vmulwev_w_hu_h(t1, a, b); ++ tcg_gen_add_i32(t, t, t1); ++} ++ ++static void gen_vmaddwev_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1; ++ ++ t1 = tcg_temp_new_i64(); ++ gen_vmulwev_d_wu_w(t1, a, b); ++ tcg_gen_add_i64(t, t, t1); ++} ++ ++static void do_vmaddwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shli_vec, INDEX_op_sari_vec, ++ INDEX_op_mul_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmaddwev_u_s, ++ .fno = gen_helper_vmaddwev_h_bu_b, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmaddwev_w_hu_h, ++ .fniv = gen_vmaddwev_u_s, ++ .fno = gen_helper_vmaddwev_w_hu_h, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmaddwev_d_wu_w, ++ .fniv = gen_vmaddwev_u_s, ++ .fno = gen_helper_vmaddwev_d_wu_w, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmaddwev_h_bu_b, LSX, gvec_vvv, MO_8, do_vmaddwev_u_s) ++TRANS(vmaddwev_w_hu_h, LSX, gvec_vvv, MO_16, do_vmaddwev_u_s) ++TRANS(vmaddwev_d_wu_w, LSX, gvec_vvv, MO_32, do_vmaddwev_u_s) ++TRANS(xvmaddwev_h_bu_b, LASX, gvec_xxx, MO_8, do_vmaddwev_u_s) ++TRANS(xvmaddwev_w_hu_h, LASX, gvec_xxx, MO_16, do_vmaddwev_u_s) ++TRANS(xvmaddwev_d_wu_w, LASX, gvec_xxx, MO_32, do_vmaddwev_u_s) ++ ++static void gen_vmaddwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, t2, t3; ++ int halfbits = 4 << vece; ++ ++ t1 = tcg_temp_new_vec_matching(a); ++ t2 = tcg_temp_new_vec_matching(b); ++ t3 = tcg_temp_new_vec_matching(t); ++ tcg_gen_shri_vec(vece, t1, a, halfbits); ++ tcg_gen_sari_vec(vece, t2, b, halfbits); ++ tcg_gen_mul_vec(vece, t3, t1, t2); ++ tcg_gen_add_vec(vece, t, t, t3); ++} ++ ++static void gen_vmaddwod_w_hu_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) ++{ ++ TCGv_i32 t1; ++ ++ t1 = tcg_temp_new_i32(); ++ gen_vmulwod_w_hu_h(t1, a, b); ++ tcg_gen_add_i32(t, t, t1); ++} ++ ++static void gen_vmaddwod_d_wu_w(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) ++{ ++ TCGv_i64 t1; ++ ++ t1 = tcg_temp_new_i64(); ++ gen_vmulwod_d_wu_w(t1, a, b); ++ tcg_gen_add_i64(t, t, t1); ++} ++ ++static void do_vmaddwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shri_vec, INDEX_op_sari_vec, ++ INDEX_op_mul_vec, INDEX_op_add_vec, 0 ++ }; ++ static const GVecGen3 op[3] = { ++ { ++ .fniv = gen_vmaddwod_u_s, ++ .fno = gen_helper_vmaddwod_h_bu_b, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fni4 = gen_vmaddwod_w_hu_h, ++ .fniv = gen_vmaddwod_u_s, ++ .fno = gen_helper_vmaddwod_w_hu_h, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fni8 = gen_vmaddwod_d_wu_w, ++ .fniv = gen_vmaddwod_u_s, ++ .fno = gen_helper_vmaddwod_d_wu_w, ++ .load_dest = true, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vmaddwod_h_bu_b, LSX, gvec_vvv, MO_8, do_vmaddwod_u_s) ++TRANS(vmaddwod_w_hu_h, LSX, gvec_vvv, MO_16, do_vmaddwod_u_s) ++TRANS(vmaddwod_d_wu_w, LSX, gvec_vvv, MO_32, do_vmaddwod_u_s) ++TRANS(xvmaddwod_h_bu_b, LASX, gvec_xxx, MO_8, do_vmaddwod_u_s) ++TRANS(xvmaddwod_w_hu_h, LASX, gvec_xxx, MO_16, do_vmaddwod_u_s) ++TRANS(xvmaddwod_d_wu_w, LASX, gvec_xxx, MO_32, do_vmaddwod_u_s) ++ ++TRANS(vdiv_b, LSX, gen_vvv, gen_helper_vdiv_b) ++TRANS(vdiv_h, LSX, gen_vvv, gen_helper_vdiv_h) ++TRANS(vdiv_w, LSX, gen_vvv, gen_helper_vdiv_w) ++TRANS(vdiv_d, LSX, gen_vvv, gen_helper_vdiv_d) ++TRANS(vdiv_bu, LSX, gen_vvv, gen_helper_vdiv_bu) ++TRANS(vdiv_hu, LSX, gen_vvv, gen_helper_vdiv_hu) ++TRANS(vdiv_wu, LSX, gen_vvv, gen_helper_vdiv_wu) ++TRANS(vdiv_du, LSX, gen_vvv, gen_helper_vdiv_du) ++TRANS(vmod_b, LSX, gen_vvv, gen_helper_vmod_b) ++TRANS(vmod_h, LSX, gen_vvv, gen_helper_vmod_h) ++TRANS(vmod_w, LSX, gen_vvv, gen_helper_vmod_w) ++TRANS(vmod_d, LSX, gen_vvv, gen_helper_vmod_d) ++TRANS(vmod_bu, LSX, gen_vvv, gen_helper_vmod_bu) ++TRANS(vmod_hu, LSX, gen_vvv, gen_helper_vmod_hu) ++TRANS(vmod_wu, LSX, gen_vvv, gen_helper_vmod_wu) ++TRANS(vmod_du, LSX, gen_vvv, gen_helper_vmod_du) ++TRANS(xvdiv_b, LASX, gen_xxx, gen_helper_vdiv_b) ++TRANS(xvdiv_h, LASX, gen_xxx, gen_helper_vdiv_h) ++TRANS(xvdiv_w, LASX, gen_xxx, gen_helper_vdiv_w) ++TRANS(xvdiv_d, LASX, gen_xxx, gen_helper_vdiv_d) ++TRANS(xvdiv_bu, LASX, gen_xxx, gen_helper_vdiv_bu) ++TRANS(xvdiv_hu, LASX, gen_xxx, gen_helper_vdiv_hu) ++TRANS(xvdiv_wu, LASX, gen_xxx, gen_helper_vdiv_wu) ++TRANS(xvdiv_du, LASX, gen_xxx, gen_helper_vdiv_du) ++TRANS(xvmod_b, LASX, gen_xxx, gen_helper_vmod_b) ++TRANS(xvmod_h, LASX, gen_xxx, gen_helper_vmod_h) ++TRANS(xvmod_w, LASX, gen_xxx, gen_helper_vmod_w) ++TRANS(xvmod_d, LASX, gen_xxx, gen_helper_vmod_d) ++TRANS(xvmod_bu, LASX, gen_xxx, gen_helper_vmod_bu) ++TRANS(xvmod_hu, LASX, gen_xxx, gen_helper_vmod_hu) ++TRANS(xvmod_wu, LASX, gen_xxx, gen_helper_vmod_wu) ++TRANS(xvmod_du, LASX, gen_xxx, gen_helper_vmod_du) ++ ++static void gen_vsat_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec max) ++{ ++ TCGv_vec min; ++ ++ min = tcg_temp_new_vec_matching(t); ++ tcg_gen_not_vec(vece, min, max); ++ tcg_gen_smax_vec(vece, t, a, min); ++ tcg_gen_smin_vec(vece, t, t, max); ++} ++ ++static void do_vsat_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ int64_t imm, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_smax_vec, INDEX_op_smin_vec, 0 ++ }; ++ static const GVecGen2s op[4] = { ++ { ++ .fniv = gen_vsat_s, ++ .fno = gen_helper_vsat_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vsat_s, ++ .fno = gen_helper_vsat_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vsat_s, ++ .fno = gen_helper_vsat_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vsat_s, ++ .fno = gen_helper_vsat_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_2s(vd_ofs, vj_ofs, oprsz, maxsz, ++ tcg_constant_i64((1ll<< imm) -1), &op[vece]); ++} ++ ++TRANS(vsat_b, LSX, gvec_vv_i, MO_8, do_vsat_s) ++TRANS(vsat_h, LSX, gvec_vv_i, MO_16, do_vsat_s) ++TRANS(vsat_w, LSX, gvec_vv_i, MO_32, do_vsat_s) ++TRANS(vsat_d, LSX, gvec_vv_i, MO_64, do_vsat_s) ++TRANS(xvsat_b, LASX, gvec_xx_i, MO_8, do_vsat_s) ++TRANS(xvsat_h, LASX, gvec_xx_i, MO_16, do_vsat_s) ++TRANS(xvsat_w, LASX, gvec_xx_i, MO_32, do_vsat_s) ++TRANS(xvsat_d, LASX, gvec_xx_i, MO_64, do_vsat_s) ++ ++static void gen_vsat_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec max) ++{ ++ tcg_gen_umin_vec(vece, t, a, max); ++} ++ ++static void do_vsat_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ int64_t imm, uint32_t oprsz, uint32_t maxsz) ++{ ++ uint64_t max; ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_umin_vec, 0 ++ }; ++ static const GVecGen2s op[4] = { ++ { ++ .fniv = gen_vsat_u, ++ .fno = gen_helper_vsat_bu, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vsat_u, ++ .fno = gen_helper_vsat_hu, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vsat_u, ++ .fno = gen_helper_vsat_wu, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vsat_u, ++ .fno = gen_helper_vsat_du, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ max = (imm == 0x3f) ? UINT64_MAX : (1ull << (imm + 1)) - 1; ++ tcg_gen_gvec_2s(vd_ofs, vj_ofs, oprsz, maxsz, ++ tcg_constant_i64(max), &op[vece]); ++} ++ ++TRANS(vsat_bu, LSX, gvec_vv_i, MO_8, do_vsat_u) ++TRANS(vsat_hu, LSX, gvec_vv_i, MO_16, do_vsat_u) ++TRANS(vsat_wu, LSX, gvec_vv_i, MO_32, do_vsat_u) ++TRANS(vsat_du, LSX, gvec_vv_i, MO_64, do_vsat_u) ++TRANS(xvsat_bu, LASX, gvec_xx_i, MO_8, do_vsat_u) ++TRANS(xvsat_hu, LASX, gvec_xx_i, MO_16, do_vsat_u) ++TRANS(xvsat_wu, LASX, gvec_xx_i, MO_32, do_vsat_u) ++TRANS(xvsat_du, LASX, gvec_xx_i, MO_64, do_vsat_u) ++ ++TRANS(vexth_h_b, LSX, gen_vv, gen_helper_vexth_h_b) ++TRANS(vexth_w_h, LSX, gen_vv, gen_helper_vexth_w_h) ++TRANS(vexth_d_w, LSX, gen_vv, gen_helper_vexth_d_w) ++TRANS(vexth_q_d, LSX, gen_vv, gen_helper_vexth_q_d) ++TRANS(vexth_hu_bu, LSX, gen_vv, gen_helper_vexth_hu_bu) ++TRANS(vexth_wu_hu, LSX, gen_vv, gen_helper_vexth_wu_hu) ++TRANS(vexth_du_wu, LSX, gen_vv, gen_helper_vexth_du_wu) ++TRANS(vexth_qu_du, LSX, gen_vv, gen_helper_vexth_qu_du) ++TRANS(xvexth_h_b, LASX, gen_xx, gen_helper_vexth_h_b) ++TRANS(xvexth_w_h, LASX, gen_xx, gen_helper_vexth_w_h) ++TRANS(xvexth_d_w, LASX, gen_xx, gen_helper_vexth_d_w) ++TRANS(xvexth_q_d, LASX, gen_xx, gen_helper_vexth_q_d) ++TRANS(xvexth_hu_bu, LASX, gen_xx, gen_helper_vexth_hu_bu) ++TRANS(xvexth_wu_hu, LASX, gen_xx, gen_helper_vexth_wu_hu) ++TRANS(xvexth_du_wu, LASX, gen_xx, gen_helper_vexth_du_wu) ++TRANS(xvexth_qu_du, LASX, gen_xx, gen_helper_vexth_qu_du) ++ ++TRANS(vext2xv_h_b, LASX, gen_xx, gen_helper_vext2xv_h_b) ++TRANS(vext2xv_w_b, LASX, gen_xx, gen_helper_vext2xv_w_b) ++TRANS(vext2xv_d_b, LASX, gen_xx, gen_helper_vext2xv_d_b) ++TRANS(vext2xv_w_h, LASX, gen_xx, gen_helper_vext2xv_w_h) ++TRANS(vext2xv_d_h, LASX, gen_xx, gen_helper_vext2xv_d_h) ++TRANS(vext2xv_d_w, LASX, gen_xx, gen_helper_vext2xv_d_w) ++TRANS(vext2xv_hu_bu, LASX, gen_xx, gen_helper_vext2xv_hu_bu) ++TRANS(vext2xv_wu_bu, LASX, gen_xx, gen_helper_vext2xv_wu_bu) ++TRANS(vext2xv_du_bu, LASX, gen_xx, gen_helper_vext2xv_du_bu) ++TRANS(vext2xv_wu_hu, LASX, gen_xx, gen_helper_vext2xv_wu_hu) ++TRANS(vext2xv_du_hu, LASX, gen_xx, gen_helper_vext2xv_du_hu) ++TRANS(vext2xv_du_wu, LASX, gen_xx, gen_helper_vext2xv_du_wu) ++ ++static void gen_vsigncov(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ TCGv_vec t1, zero; ++ ++ t1 = tcg_temp_new_vec_matching(t); ++ zero = tcg_constant_vec_matching(t, vece, 0); ++ ++ tcg_gen_neg_vec(vece, t1, b); ++ tcg_gen_cmpsel_vec(TCG_COND_LT, vece, t, a, zero, t1, b); ++ tcg_gen_cmpsel_vec(TCG_COND_EQ, vece, t, a, zero, zero, t); ++} ++ ++static void do_vsigncov(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_neg_vec, INDEX_op_cmpsel_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vsigncov, ++ .fno = gen_helper_vsigncov_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vsigncov, ++ .fno = gen_helper_vsigncov_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vsigncov, ++ .fno = gen_helper_vsigncov_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vsigncov, ++ .fno = gen_helper_vsigncov_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vsigncov_b, LSX, gvec_vvv, MO_8, do_vsigncov) ++TRANS(vsigncov_h, LSX, gvec_vvv, MO_16, do_vsigncov) ++TRANS(vsigncov_w, LSX, gvec_vvv, MO_32, do_vsigncov) ++TRANS(vsigncov_d, LSX, gvec_vvv, MO_64, do_vsigncov) ++TRANS(xvsigncov_b, LASX, gvec_xxx, MO_8, do_vsigncov) ++TRANS(xvsigncov_h, LASX, gvec_xxx, MO_16, do_vsigncov) ++TRANS(xvsigncov_w, LASX, gvec_xxx, MO_32, do_vsigncov) ++TRANS(xvsigncov_d, LASX, gvec_xxx, MO_64, do_vsigncov) ++ ++TRANS(vmskltz_b, LSX, gen_vv, gen_helper_vmskltz_b) ++TRANS(vmskltz_h, LSX, gen_vv, gen_helper_vmskltz_h) ++TRANS(vmskltz_w, LSX, gen_vv, gen_helper_vmskltz_w) ++TRANS(vmskltz_d, LSX, gen_vv, gen_helper_vmskltz_d) ++TRANS(vmskgez_b, LSX, gen_vv, gen_helper_vmskgez_b) ++TRANS(vmsknz_b, LSX, gen_vv, gen_helper_vmsknz_b) ++TRANS(xvmskltz_b, LASX, gen_xx, gen_helper_vmskltz_b) ++TRANS(xvmskltz_h, LASX, gen_xx, gen_helper_vmskltz_h) ++TRANS(xvmskltz_w, LASX, gen_xx, gen_helper_vmskltz_w) ++TRANS(xvmskltz_d, LASX, gen_xx, gen_helper_vmskltz_d) ++TRANS(xvmskgez_b, LASX, gen_xx, gen_helper_vmskgez_b) ++TRANS(xvmsknz_b, LASX, gen_xx, gen_helper_vmsknz_b) ++ ++#define EXPAND_BYTE(bit) ((uint64_t)(bit ? 0xff : 0)) ++ ++static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm) ++{ ++ int mode; ++ uint64_t data, t; ++ ++ /* ++ * imm bit [11:8] is mode, mode value is 0-12. ++ * other values are invalid. ++ */ ++ mode = (imm >> 8) & 0xf; ++ t = imm & 0xff; ++ switch (mode) { ++ case 0: ++ /* data: {2{24'0, imm[7:0]}} */ ++ data = (t << 32) | t ; ++ break; ++ case 1: ++ /* data: {2{16'0, imm[7:0], 8'0}} */ ++ data = (t << 24) | (t << 8); ++ break; ++ case 2: ++ /* data: {2{8'0, imm[7:0], 16'0}} */ ++ data = (t << 48) | (t << 16); ++ break; ++ case 3: ++ /* data: {2{imm[7:0], 24'0}} */ ++ data = (t << 56) | (t << 24); ++ break; ++ case 4: ++ /* data: {4{8'0, imm[7:0]}} */ ++ data = (t << 48) | (t << 32) | (t << 16) | t; ++ break; ++ case 5: ++ /* data: {4{imm[7:0], 8'0}} */ ++ data = (t << 56) |(t << 40) | (t << 24) | (t << 8); ++ break; ++ case 6: ++ /* data: {2{16'0, imm[7:0], 8'1}} */ ++ data = (t << 40) | ((uint64_t)0xff << 32) | (t << 8) | 0xff; ++ break; ++ case 7: ++ /* data: {2{8'0, imm[7:0], 16'1}} */ ++ data = (t << 48) | ((uint64_t)0xffff << 32) | (t << 16) | 0xffff; ++ break; ++ case 8: ++ /* data: {8{imm[7:0]}} */ ++ data =(t << 56) | (t << 48) | (t << 40) | (t << 32) | ++ (t << 24) | (t << 16) | (t << 8) | t; ++ break; ++ case 9: ++ /* data: {{8{imm[7]}, ..., 8{imm[0]}}} */ ++ { ++ uint64_t b0,b1,b2,b3,b4,b5,b6,b7; ++ b0 = t& 0x1; ++ b1 = (t & 0x2) >> 1; ++ b2 = (t & 0x4) >> 2; ++ b3 = (t & 0x8) >> 3; ++ b4 = (t & 0x10) >> 4; ++ b5 = (t & 0x20) >> 5; ++ b6 = (t & 0x40) >> 6; ++ b7 = (t & 0x80) >> 7; ++ data = (EXPAND_BYTE(b7) << 56) | ++ (EXPAND_BYTE(b6) << 48) | ++ (EXPAND_BYTE(b5) << 40) | ++ (EXPAND_BYTE(b4) << 32) | ++ (EXPAND_BYTE(b3) << 24) | ++ (EXPAND_BYTE(b2) << 16) | ++ (EXPAND_BYTE(b1) << 8) | ++ EXPAND_BYTE(b0); ++ } ++ break; ++ case 10: ++ /* data: {2{imm[7], ~imm[6], {5{imm[6]}}, imm[5:0], 19'0}} */ ++ { ++ uint64_t b6, b7; ++ uint64_t t0, t1; ++ b6 = (imm & 0x40) >> 6; ++ b7 = (imm & 0x80) >> 7; ++ t0 = (imm & 0x3f); ++ t1 = (b7 << 6) | ((1-b6) << 5) | (uint64_t)(b6 ? 0x1f : 0); ++ data = (t1 << 57) | (t0 << 51) | (t1 << 25) | (t0 << 19); ++ } ++ break; ++ case 11: ++ /* data: {32'0, imm[7], ~{imm[6]}, 5{imm[6]}, imm[5:0], 19'0} */ ++ { ++ uint64_t b6,b7; ++ uint64_t t0, t1; ++ b6 = (imm & 0x40) >> 6; ++ b7 = (imm & 0x80) >> 7; ++ t0 = (imm & 0x3f); ++ t1 = (b7 << 6) | ((1-b6) << 5) | (b6 ? 0x1f : 0); ++ data = (t1 << 25) | (t0 << 19); ++ } ++ break; ++ case 12: ++ /* data: {imm[7], ~imm[6], 8{imm[6]}, imm[5:0], 48'0} */ ++ { ++ uint64_t b6,b7; ++ uint64_t t0, t1; ++ b6 = (imm & 0x40) >> 6; ++ b7 = (imm & 0x80) >> 7; ++ t0 = (imm & 0x3f); ++ t1 = (b7 << 9) | ((1-b6) << 8) | (b6 ? 0xff : 0); ++ data = (t1 << 54) | (t0 << 48); ++ } ++ break; ++ default: ++ generate_exception(ctx, EXCCODE_INE); ++ g_assert_not_reached(); ++ } ++ return data; ++} ++ ++static bool gen_vldi(DisasContext *ctx, arg_vldi *a, uint32_t oprsz) ++{ ++ int sel, vece; ++ uint64_t value; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ sel = (a->imm >> 12) & 0x1; ++ ++ if (sel) { ++ value = vldi_get_value(ctx, a->imm); ++ vece = MO_64; ++ } else { ++ value = ((int32_t)(a->imm << 22)) >> 22; ++ vece = (a->imm >> 10) & 0x3; ++ } ++ ++ tcg_gen_gvec_dup_i64(vece, vec_full_offset(a->vd), oprsz, ctx->vl/8, ++ tcg_constant_i64(value)); ++ return true; ++} ++ ++TRANS(vldi, LSX, gen_vldi, 16) ++TRANS(xvldi, LASX, gen_vldi, 32) ++ ++static bool gen_vandn_v(DisasContext *ctx, arg_vvv *a, uint32_t oprsz) ++{ ++ uint32_t vd_ofs, vj_ofs, vk_ofs; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ vd_ofs = vec_full_offset(a->vd); ++ vj_ofs = vec_full_offset(a->vj); ++ vk_ofs = vec_full_offset(a->vk); ++ ++ tcg_gen_gvec_andc(MO_64, vd_ofs, vk_ofs, vj_ofs, oprsz, ctx->vl / 8); ++ return true; ++} ++ ++static void gen_vnori(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) ++{ ++ TCGv_vec t1; ++ ++ t1 = tcg_constant_vec_matching(t, vece, imm); ++ tcg_gen_nor_vec(vece, t, a, t1); ++} ++ ++static void gen_vnori_b(TCGv_i64 t, TCGv_i64 a, int64_t imm) ++{ ++ tcg_gen_movi_i64(t, dup_const(MO_8, imm)); ++ tcg_gen_nor_i64(t, a, t); ++} ++ ++static void do_vnori_b(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ int64_t imm, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_nor_vec, 0 ++ }; ++ static const GVecGen2i op = { ++ .fni8 = gen_vnori_b, ++ .fniv = gen_vnori, ++ .fnoi = gen_helper_vnori_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }; ++ ++ tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op); ++} ++ ++TRANS(vand_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_and) ++TRANS(vor_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_or) ++TRANS(vxor_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_xor) ++TRANS(vnor_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_nor) ++TRANS(vandn_v, LSX, gen_vandn_v, 16) ++TRANS(vorn_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_orc) ++TRANS(vandi_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_andi) ++TRANS(vori_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_ori) ++TRANS(vxori_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_xori) ++TRANS(vnori_b, LSX, gvec_vv_i, MO_8, do_vnori_b) ++TRANS(xvand_v, LASX, gvec_xxx, MO_64, tcg_gen_gvec_and) ++TRANS(xvor_v, LASX, gvec_xxx, MO_64, tcg_gen_gvec_or) ++TRANS(xvxor_v, LASX, gvec_xxx, MO_64, tcg_gen_gvec_xor) ++TRANS(xvnor_v, LASX, gvec_xxx, MO_64, tcg_gen_gvec_nor) ++TRANS(xvandn_v, LASX, gen_vandn_v, 32) ++TRANS(xvorn_v, LASX, gvec_xxx, MO_64, tcg_gen_gvec_orc) ++TRANS(xvandi_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_andi) ++TRANS(xvori_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_ori) ++TRANS(xvxori_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_xori) ++TRANS(xvnori_b, LASX, gvec_xx_i, MO_8, do_vnori_b) ++ ++TRANS(vsll_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_shlv) ++TRANS(vsll_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_shlv) ++TRANS(vsll_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_shlv) ++TRANS(vsll_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_shlv) ++TRANS(vslli_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_shli) ++TRANS(vslli_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_shli) ++TRANS(vslli_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_shli) ++TRANS(vslli_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_shli) ++TRANS(xvsll_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_shlv) ++TRANS(xvsll_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_shlv) ++TRANS(xvsll_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_shlv) ++TRANS(xvsll_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_shlv) ++TRANS(xvslli_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_shli) ++TRANS(xvslli_h, LASX, gvec_xx_i, MO_16, tcg_gen_gvec_shli) ++TRANS(xvslli_w, LASX, gvec_xx_i, MO_32, tcg_gen_gvec_shli) ++TRANS(xvslli_d, LASX, gvec_xx_i, MO_64, tcg_gen_gvec_shli) ++ ++TRANS(vsrl_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_shrv) ++TRANS(vsrl_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_shrv) ++TRANS(vsrl_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_shrv) ++TRANS(vsrl_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_shrv) ++TRANS(vsrli_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_shri) ++TRANS(vsrli_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_shri) ++TRANS(vsrli_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_shri) ++TRANS(vsrli_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_shri) ++TRANS(xvsrl_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_shrv) ++TRANS(xvsrl_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_shrv) ++TRANS(xvsrl_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_shrv) ++TRANS(xvsrl_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_shrv) ++TRANS(xvsrli_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_shri) ++TRANS(xvsrli_h, LASX, gvec_xx_i, MO_16, tcg_gen_gvec_shri) ++TRANS(xvsrli_w, LASX, gvec_xx_i, MO_32, tcg_gen_gvec_shri) ++TRANS(xvsrli_d, LASX, gvec_xx_i, MO_64, tcg_gen_gvec_shri) ++ ++TRANS(vsra_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_sarv) ++TRANS(vsra_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_sarv) ++TRANS(vsra_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_sarv) ++TRANS(vsra_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_sarv) ++TRANS(vsrai_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_sari) ++TRANS(vsrai_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_sari) ++TRANS(vsrai_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_sari) ++TRANS(vsrai_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_sari) ++TRANS(xvsra_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_sarv) ++TRANS(xvsra_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_sarv) ++TRANS(xvsra_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_sarv) ++TRANS(xvsra_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_sarv) ++TRANS(xvsrai_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_sari) ++TRANS(xvsrai_h, LASX, gvec_xx_i, MO_16, tcg_gen_gvec_sari) ++TRANS(xvsrai_w, LASX, gvec_xx_i, MO_32, tcg_gen_gvec_sari) ++TRANS(xvsrai_d, LASX, gvec_xx_i, MO_64, tcg_gen_gvec_sari) ++ ++TRANS(vrotr_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_rotrv) ++TRANS(vrotr_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_rotrv) ++TRANS(vrotr_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_rotrv) ++TRANS(vrotr_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_rotrv) ++TRANS(vrotri_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_rotri) ++TRANS(vrotri_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_rotri) ++TRANS(vrotri_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_rotri) ++TRANS(vrotri_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_rotri) ++TRANS(xvrotr_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_rotrv) ++TRANS(xvrotr_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_rotrv) ++TRANS(xvrotr_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_rotrv) ++TRANS(xvrotr_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_rotrv) ++TRANS(xvrotri_b, LASX, gvec_xx_i, MO_8, tcg_gen_gvec_rotri) ++TRANS(xvrotri_h, LASX, gvec_xx_i, MO_16, tcg_gen_gvec_rotri) ++TRANS(xvrotri_w, LASX, gvec_xx_i, MO_32, tcg_gen_gvec_rotri) ++TRANS(xvrotri_d, LASX, gvec_xx_i, MO_64, tcg_gen_gvec_rotri) ++ ++TRANS(vsllwil_h_b, LSX, gen_vv_i, gen_helper_vsllwil_h_b) ++TRANS(vsllwil_w_h, LSX, gen_vv_i, gen_helper_vsllwil_w_h) ++TRANS(vsllwil_d_w, LSX, gen_vv_i, gen_helper_vsllwil_d_w) ++TRANS(vextl_q_d, LSX, gen_vv, gen_helper_vextl_q_d) ++TRANS(vsllwil_hu_bu, LSX, gen_vv_i, gen_helper_vsllwil_hu_bu) ++TRANS(vsllwil_wu_hu, LSX, gen_vv_i, gen_helper_vsllwil_wu_hu) ++TRANS(vsllwil_du_wu, LSX, gen_vv_i, gen_helper_vsllwil_du_wu) ++TRANS(vextl_qu_du, LSX, gen_vv, gen_helper_vextl_qu_du) ++TRANS(xvsllwil_h_b, LASX, gen_xx_i, gen_helper_vsllwil_h_b) ++TRANS(xvsllwil_w_h, LASX, gen_xx_i, gen_helper_vsllwil_w_h) ++TRANS(xvsllwil_d_w, LASX, gen_xx_i, gen_helper_vsllwil_d_w) ++TRANS(xvextl_q_d, LASX, gen_xx, gen_helper_vextl_q_d) ++TRANS(xvsllwil_hu_bu, LASX, gen_xx_i, gen_helper_vsllwil_hu_bu) ++TRANS(xvsllwil_wu_hu, LASX, gen_xx_i, gen_helper_vsllwil_wu_hu) ++TRANS(xvsllwil_du_wu, LASX, gen_xx_i, gen_helper_vsllwil_du_wu) ++TRANS(xvextl_qu_du, LASX, gen_xx, gen_helper_vextl_qu_du) ++ ++TRANS(vsrlr_b, LSX, gen_vvv, gen_helper_vsrlr_b) ++TRANS(vsrlr_h, LSX, gen_vvv, gen_helper_vsrlr_h) ++TRANS(vsrlr_w, LSX, gen_vvv, gen_helper_vsrlr_w) ++TRANS(vsrlr_d, LSX, gen_vvv, gen_helper_vsrlr_d) ++TRANS(vsrlri_b, LSX, gen_vv_i, gen_helper_vsrlri_b) ++TRANS(vsrlri_h, LSX, gen_vv_i, gen_helper_vsrlri_h) ++TRANS(vsrlri_w, LSX, gen_vv_i, gen_helper_vsrlri_w) ++TRANS(vsrlri_d, LSX, gen_vv_i, gen_helper_vsrlri_d) ++TRANS(xvsrlr_b, LASX, gen_xxx, gen_helper_vsrlr_b) ++TRANS(xvsrlr_h, LASX, gen_xxx, gen_helper_vsrlr_h) ++TRANS(xvsrlr_w, LASX, gen_xxx, gen_helper_vsrlr_w) ++TRANS(xvsrlr_d, LASX, gen_xxx, gen_helper_vsrlr_d) ++TRANS(xvsrlri_b, LASX, gen_xx_i, gen_helper_vsrlri_b) ++TRANS(xvsrlri_h, LASX, gen_xx_i, gen_helper_vsrlri_h) ++TRANS(xvsrlri_w, LASX, gen_xx_i, gen_helper_vsrlri_w) ++TRANS(xvsrlri_d, LASX, gen_xx_i, gen_helper_vsrlri_d) ++ ++TRANS(vsrar_b, LSX, gen_vvv, gen_helper_vsrar_b) ++TRANS(vsrar_h, LSX, gen_vvv, gen_helper_vsrar_h) ++TRANS(vsrar_w, LSX, gen_vvv, gen_helper_vsrar_w) ++TRANS(vsrar_d, LSX, gen_vvv, gen_helper_vsrar_d) ++TRANS(vsrari_b, LSX, gen_vv_i, gen_helper_vsrari_b) ++TRANS(vsrari_h, LSX, gen_vv_i, gen_helper_vsrari_h) ++TRANS(vsrari_w, LSX, gen_vv_i, gen_helper_vsrari_w) ++TRANS(vsrari_d, LSX, gen_vv_i, gen_helper_vsrari_d) ++TRANS(xvsrar_b, LASX, gen_xxx, gen_helper_vsrar_b) ++TRANS(xvsrar_h, LASX, gen_xxx, gen_helper_vsrar_h) ++TRANS(xvsrar_w, LASX, gen_xxx, gen_helper_vsrar_w) ++TRANS(xvsrar_d, LASX, gen_xxx, gen_helper_vsrar_d) ++TRANS(xvsrari_b, LASX, gen_xx_i, gen_helper_vsrari_b) ++TRANS(xvsrari_h, LASX, gen_xx_i, gen_helper_vsrari_h) ++TRANS(xvsrari_w, LASX, gen_xx_i, gen_helper_vsrari_w) ++TRANS(xvsrari_d, LASX, gen_xx_i, gen_helper_vsrari_d) ++ ++TRANS(vsrln_b_h, LSX, gen_vvv, gen_helper_vsrln_b_h) ++TRANS(vsrln_h_w, LSX, gen_vvv, gen_helper_vsrln_h_w) ++TRANS(vsrln_w_d, LSX, gen_vvv, gen_helper_vsrln_w_d) ++TRANS(vsran_b_h, LSX, gen_vvv, gen_helper_vsran_b_h) ++TRANS(vsran_h_w, LSX, gen_vvv, gen_helper_vsran_h_w) ++TRANS(vsran_w_d, LSX, gen_vvv, gen_helper_vsran_w_d) ++TRANS(xvsrln_b_h, LASX, gen_xxx, gen_helper_vsrln_b_h) ++TRANS(xvsrln_h_w, LASX, gen_xxx, gen_helper_vsrln_h_w) ++TRANS(xvsrln_w_d, LASX, gen_xxx, gen_helper_vsrln_w_d) ++TRANS(xvsran_b_h, LASX, gen_xxx, gen_helper_vsran_b_h) ++TRANS(xvsran_h_w, LASX, gen_xxx, gen_helper_vsran_h_w) ++TRANS(xvsran_w_d, LASX, gen_xxx, gen_helper_vsran_w_d) ++ ++TRANS(vsrlni_b_h, LSX, gen_vv_i, gen_helper_vsrlni_b_h) ++TRANS(vsrlni_h_w, LSX, gen_vv_i, gen_helper_vsrlni_h_w) ++TRANS(vsrlni_w_d, LSX, gen_vv_i, gen_helper_vsrlni_w_d) ++TRANS(vsrlni_d_q, LSX, gen_vv_i, gen_helper_vsrlni_d_q) ++TRANS(vsrani_b_h, LSX, gen_vv_i, gen_helper_vsrani_b_h) ++TRANS(vsrani_h_w, LSX, gen_vv_i, gen_helper_vsrani_h_w) ++TRANS(vsrani_w_d, LSX, gen_vv_i, gen_helper_vsrani_w_d) ++TRANS(vsrani_d_q, LSX, gen_vv_i, gen_helper_vsrani_d_q) ++TRANS(xvsrlni_b_h, LASX, gen_xx_i, gen_helper_vsrlni_b_h) ++TRANS(xvsrlni_h_w, LASX, gen_xx_i, gen_helper_vsrlni_h_w) ++TRANS(xvsrlni_w_d, LASX, gen_xx_i, gen_helper_vsrlni_w_d) ++TRANS(xvsrlni_d_q, LASX, gen_xx_i, gen_helper_vsrlni_d_q) ++TRANS(xvsrani_b_h, LASX, gen_xx_i, gen_helper_vsrani_b_h) ++TRANS(xvsrani_h_w, LASX, gen_xx_i, gen_helper_vsrani_h_w) ++TRANS(xvsrani_w_d, LASX, gen_xx_i, gen_helper_vsrani_w_d) ++TRANS(xvsrani_d_q, LASX, gen_xx_i, gen_helper_vsrani_d_q) ++ ++TRANS(vsrlrn_b_h, LSX, gen_vvv, gen_helper_vsrlrn_b_h) ++TRANS(vsrlrn_h_w, LSX, gen_vvv, gen_helper_vsrlrn_h_w) ++TRANS(vsrlrn_w_d, LSX, gen_vvv, gen_helper_vsrlrn_w_d) ++TRANS(vsrarn_b_h, LSX, gen_vvv, gen_helper_vsrarn_b_h) ++TRANS(vsrarn_h_w, LSX, gen_vvv, gen_helper_vsrarn_h_w) ++TRANS(vsrarn_w_d, LSX, gen_vvv, gen_helper_vsrarn_w_d) ++TRANS(xvsrlrn_b_h, LASX, gen_xxx, gen_helper_vsrlrn_b_h) ++TRANS(xvsrlrn_h_w, LASX, gen_xxx, gen_helper_vsrlrn_h_w) ++TRANS(xvsrlrn_w_d, LASX, gen_xxx, gen_helper_vsrlrn_w_d) ++TRANS(xvsrarn_b_h, LASX, gen_xxx, gen_helper_vsrarn_b_h) ++TRANS(xvsrarn_h_w, LASX, gen_xxx, gen_helper_vsrarn_h_w) ++TRANS(xvsrarn_w_d, LASX, gen_xxx, gen_helper_vsrarn_w_d) ++ ++TRANS(vsrlrni_b_h, LSX, gen_vv_i, gen_helper_vsrlrni_b_h) ++TRANS(vsrlrni_h_w, LSX, gen_vv_i, gen_helper_vsrlrni_h_w) ++TRANS(vsrlrni_w_d, LSX, gen_vv_i, gen_helper_vsrlrni_w_d) ++TRANS(vsrlrni_d_q, LSX, gen_vv_i, gen_helper_vsrlrni_d_q) ++TRANS(vsrarni_b_h, LSX, gen_vv_i, gen_helper_vsrarni_b_h) ++TRANS(vsrarni_h_w, LSX, gen_vv_i, gen_helper_vsrarni_h_w) ++TRANS(vsrarni_w_d, LSX, gen_vv_i, gen_helper_vsrarni_w_d) ++TRANS(vsrarni_d_q, LSX, gen_vv_i, gen_helper_vsrarni_d_q) ++TRANS(xvsrlrni_b_h, LASX, gen_xx_i, gen_helper_vsrlrni_b_h) ++TRANS(xvsrlrni_h_w, LASX, gen_xx_i, gen_helper_vsrlrni_h_w) ++TRANS(xvsrlrni_w_d, LASX, gen_xx_i, gen_helper_vsrlrni_w_d) ++TRANS(xvsrlrni_d_q, LASX, gen_xx_i, gen_helper_vsrlrni_d_q) ++TRANS(xvsrarni_b_h, LASX, gen_xx_i, gen_helper_vsrarni_b_h) ++TRANS(xvsrarni_h_w, LASX, gen_xx_i, gen_helper_vsrarni_h_w) ++TRANS(xvsrarni_w_d, LASX, gen_xx_i, gen_helper_vsrarni_w_d) ++TRANS(xvsrarni_d_q, LASX, gen_xx_i, gen_helper_vsrarni_d_q) ++ ++TRANS(vssrln_b_h, LSX, gen_vvv, gen_helper_vssrln_b_h) ++TRANS(vssrln_h_w, LSX, gen_vvv, gen_helper_vssrln_h_w) ++TRANS(vssrln_w_d, LSX, gen_vvv, gen_helper_vssrln_w_d) ++TRANS(vssran_b_h, LSX, gen_vvv, gen_helper_vssran_b_h) ++TRANS(vssran_h_w, LSX, gen_vvv, gen_helper_vssran_h_w) ++TRANS(vssran_w_d, LSX, gen_vvv, gen_helper_vssran_w_d) ++TRANS(vssrln_bu_h, LSX, gen_vvv, gen_helper_vssrln_bu_h) ++TRANS(vssrln_hu_w, LSX, gen_vvv, gen_helper_vssrln_hu_w) ++TRANS(vssrln_wu_d, LSX, gen_vvv, gen_helper_vssrln_wu_d) ++TRANS(vssran_bu_h, LSX, gen_vvv, gen_helper_vssran_bu_h) ++TRANS(vssran_hu_w, LSX, gen_vvv, gen_helper_vssran_hu_w) ++TRANS(vssran_wu_d, LSX, gen_vvv, gen_helper_vssran_wu_d) ++TRANS(xvssrln_b_h, LASX, gen_xxx, gen_helper_vssrln_b_h) ++TRANS(xvssrln_h_w, LASX, gen_xxx, gen_helper_vssrln_h_w) ++TRANS(xvssrln_w_d, LASX, gen_xxx, gen_helper_vssrln_w_d) ++TRANS(xvssran_b_h, LASX, gen_xxx, gen_helper_vssran_b_h) ++TRANS(xvssran_h_w, LASX, gen_xxx, gen_helper_vssran_h_w) ++TRANS(xvssran_w_d, LASX, gen_xxx, gen_helper_vssran_w_d) ++TRANS(xvssrln_bu_h, LASX, gen_xxx, gen_helper_vssrln_bu_h) ++TRANS(xvssrln_hu_w, LASX, gen_xxx, gen_helper_vssrln_hu_w) ++TRANS(xvssrln_wu_d, LASX, gen_xxx, gen_helper_vssrln_wu_d) ++TRANS(xvssran_bu_h, LASX, gen_xxx, gen_helper_vssran_bu_h) ++TRANS(xvssran_hu_w, LASX, gen_xxx, gen_helper_vssran_hu_w) ++TRANS(xvssran_wu_d, LASX, gen_xxx, gen_helper_vssran_wu_d) ++ ++TRANS(vssrlni_b_h, LSX, gen_vv_i, gen_helper_vssrlni_b_h) ++TRANS(vssrlni_h_w, LSX, gen_vv_i, gen_helper_vssrlni_h_w) ++TRANS(vssrlni_w_d, LSX, gen_vv_i, gen_helper_vssrlni_w_d) ++TRANS(vssrlni_d_q, LSX, gen_vv_i, gen_helper_vssrlni_d_q) ++TRANS(vssrani_b_h, LSX, gen_vv_i, gen_helper_vssrani_b_h) ++TRANS(vssrani_h_w, LSX, gen_vv_i, gen_helper_vssrani_h_w) ++TRANS(vssrani_w_d, LSX, gen_vv_i, gen_helper_vssrani_w_d) ++TRANS(vssrani_d_q, LSX, gen_vv_i, gen_helper_vssrani_d_q) ++TRANS(vssrlni_bu_h, LSX, gen_vv_i, gen_helper_vssrlni_bu_h) ++TRANS(vssrlni_hu_w, LSX, gen_vv_i, gen_helper_vssrlni_hu_w) ++TRANS(vssrlni_wu_d, LSX, gen_vv_i, gen_helper_vssrlni_wu_d) ++TRANS(vssrlni_du_q, LSX, gen_vv_i, gen_helper_vssrlni_du_q) ++TRANS(vssrani_bu_h, LSX, gen_vv_i, gen_helper_vssrani_bu_h) ++TRANS(vssrani_hu_w, LSX, gen_vv_i, gen_helper_vssrani_hu_w) ++TRANS(vssrani_wu_d, LSX, gen_vv_i, gen_helper_vssrani_wu_d) ++TRANS(vssrani_du_q, LSX, gen_vv_i, gen_helper_vssrani_du_q) ++TRANS(xvssrlni_b_h, LASX, gen_xx_i, gen_helper_vssrlni_b_h) ++TRANS(xvssrlni_h_w, LASX, gen_xx_i, gen_helper_vssrlni_h_w) ++TRANS(xvssrlni_w_d, LASX, gen_xx_i, gen_helper_vssrlni_w_d) ++TRANS(xvssrlni_d_q, LASX, gen_xx_i, gen_helper_vssrlni_d_q) ++TRANS(xvssrani_b_h, LASX, gen_xx_i, gen_helper_vssrani_b_h) ++TRANS(xvssrani_h_w, LASX, gen_xx_i, gen_helper_vssrani_h_w) ++TRANS(xvssrani_w_d, LASX, gen_xx_i, gen_helper_vssrani_w_d) ++TRANS(xvssrani_d_q, LASX, gen_xx_i, gen_helper_vssrani_d_q) ++TRANS(xvssrlni_bu_h, LASX, gen_xx_i, gen_helper_vssrlni_bu_h) ++TRANS(xvssrlni_hu_w, LASX, gen_xx_i, gen_helper_vssrlni_hu_w) ++TRANS(xvssrlni_wu_d, LASX, gen_xx_i, gen_helper_vssrlni_wu_d) ++TRANS(xvssrlni_du_q, LASX, gen_xx_i, gen_helper_vssrlni_du_q) ++TRANS(xvssrani_bu_h, LASX, gen_xx_i, gen_helper_vssrani_bu_h) ++TRANS(xvssrani_hu_w, LASX, gen_xx_i, gen_helper_vssrani_hu_w) ++TRANS(xvssrani_wu_d, LASX, gen_xx_i, gen_helper_vssrani_wu_d) ++TRANS(xvssrani_du_q, LASX, gen_xx_i, gen_helper_vssrani_du_q) ++ ++TRANS(vssrlrn_b_h, LSX, gen_vvv, gen_helper_vssrlrn_b_h) ++TRANS(vssrlrn_h_w, LSX, gen_vvv, gen_helper_vssrlrn_h_w) ++TRANS(vssrlrn_w_d, LSX, gen_vvv, gen_helper_vssrlrn_w_d) ++TRANS(vssrarn_b_h, LSX, gen_vvv, gen_helper_vssrarn_b_h) ++TRANS(vssrarn_h_w, LSX, gen_vvv, gen_helper_vssrarn_h_w) ++TRANS(vssrarn_w_d, LSX, gen_vvv, gen_helper_vssrarn_w_d) ++TRANS(vssrlrn_bu_h, LSX, gen_vvv, gen_helper_vssrlrn_bu_h) ++TRANS(vssrlrn_hu_w, LSX, gen_vvv, gen_helper_vssrlrn_hu_w) ++TRANS(vssrlrn_wu_d, LSX, gen_vvv, gen_helper_vssrlrn_wu_d) ++TRANS(vssrarn_bu_h, LSX, gen_vvv, gen_helper_vssrarn_bu_h) ++TRANS(vssrarn_hu_w, LSX, gen_vvv, gen_helper_vssrarn_hu_w) ++TRANS(vssrarn_wu_d, LSX, gen_vvv, gen_helper_vssrarn_wu_d) ++TRANS(xvssrlrn_b_h, LASX, gen_xxx, gen_helper_vssrlrn_b_h) ++TRANS(xvssrlrn_h_w, LASX, gen_xxx, gen_helper_vssrlrn_h_w) ++TRANS(xvssrlrn_w_d, LASX, gen_xxx, gen_helper_vssrlrn_w_d) ++TRANS(xvssrarn_b_h, LASX, gen_xxx, gen_helper_vssrarn_b_h) ++TRANS(xvssrarn_h_w, LASX, gen_xxx, gen_helper_vssrarn_h_w) ++TRANS(xvssrarn_w_d, LASX, gen_xxx, gen_helper_vssrarn_w_d) ++TRANS(xvssrlrn_bu_h, LASX, gen_xxx, gen_helper_vssrlrn_bu_h) ++TRANS(xvssrlrn_hu_w, LASX, gen_xxx, gen_helper_vssrlrn_hu_w) ++TRANS(xvssrlrn_wu_d, LASX, gen_xxx, gen_helper_vssrlrn_wu_d) ++TRANS(xvssrarn_bu_h, LASX, gen_xxx, gen_helper_vssrarn_bu_h) ++TRANS(xvssrarn_hu_w, LASX, gen_xxx, gen_helper_vssrarn_hu_w) ++TRANS(xvssrarn_wu_d, LASX, gen_xxx, gen_helper_vssrarn_wu_d) ++ ++TRANS(vssrlrni_b_h, LSX, gen_vv_i, gen_helper_vssrlrni_b_h) ++TRANS(vssrlrni_h_w, LSX, gen_vv_i, gen_helper_vssrlrni_h_w) ++TRANS(vssrlrni_w_d, LSX, gen_vv_i, gen_helper_vssrlrni_w_d) ++TRANS(vssrlrni_d_q, LSX, gen_vv_i, gen_helper_vssrlrni_d_q) ++TRANS(vssrarni_b_h, LSX, gen_vv_i, gen_helper_vssrarni_b_h) ++TRANS(vssrarni_h_w, LSX, gen_vv_i, gen_helper_vssrarni_h_w) ++TRANS(vssrarni_w_d, LSX, gen_vv_i, gen_helper_vssrarni_w_d) ++TRANS(vssrarni_d_q, LSX, gen_vv_i, gen_helper_vssrarni_d_q) ++TRANS(vssrlrni_bu_h, LSX, gen_vv_i, gen_helper_vssrlrni_bu_h) ++TRANS(vssrlrni_hu_w, LSX, gen_vv_i, gen_helper_vssrlrni_hu_w) ++TRANS(vssrlrni_wu_d, LSX, gen_vv_i, gen_helper_vssrlrni_wu_d) ++TRANS(vssrlrni_du_q, LSX, gen_vv_i, gen_helper_vssrlrni_du_q) ++TRANS(vssrarni_bu_h, LSX, gen_vv_i, gen_helper_vssrarni_bu_h) ++TRANS(vssrarni_hu_w, LSX, gen_vv_i, gen_helper_vssrarni_hu_w) ++TRANS(vssrarni_wu_d, LSX, gen_vv_i, gen_helper_vssrarni_wu_d) ++TRANS(vssrarni_du_q, LSX, gen_vv_i, gen_helper_vssrarni_du_q) ++TRANS(xvssrlrni_b_h, LASX, gen_xx_i, gen_helper_vssrlrni_b_h) ++TRANS(xvssrlrni_h_w, LASX, gen_xx_i, gen_helper_vssrlrni_h_w) ++TRANS(xvssrlrni_w_d, LASX, gen_xx_i, gen_helper_vssrlrni_w_d) ++TRANS(xvssrlrni_d_q, LASX, gen_xx_i, gen_helper_vssrlrni_d_q) ++TRANS(xvssrarni_b_h, LASX, gen_xx_i, gen_helper_vssrarni_b_h) ++TRANS(xvssrarni_h_w, LASX, gen_xx_i, gen_helper_vssrarni_h_w) ++TRANS(xvssrarni_w_d, LASX, gen_xx_i, gen_helper_vssrarni_w_d) ++TRANS(xvssrarni_d_q, LASX, gen_xx_i, gen_helper_vssrarni_d_q) ++TRANS(xvssrlrni_bu_h, LASX, gen_xx_i, gen_helper_vssrlrni_bu_h) ++TRANS(xvssrlrni_hu_w, LASX, gen_xx_i, gen_helper_vssrlrni_hu_w) ++TRANS(xvssrlrni_wu_d, LASX, gen_xx_i, gen_helper_vssrlrni_wu_d) ++TRANS(xvssrlrni_du_q, LASX, gen_xx_i, gen_helper_vssrlrni_du_q) ++TRANS(xvssrarni_bu_h, LASX, gen_xx_i, gen_helper_vssrarni_bu_h) ++TRANS(xvssrarni_hu_w, LASX, gen_xx_i, gen_helper_vssrarni_hu_w) ++TRANS(xvssrarni_wu_d, LASX, gen_xx_i, gen_helper_vssrarni_wu_d) ++TRANS(xvssrarni_du_q, LASX, gen_xx_i, gen_helper_vssrarni_du_q) ++ ++TRANS(vclo_b, LSX, gen_vv, gen_helper_vclo_b) ++TRANS(vclo_h, LSX, gen_vv, gen_helper_vclo_h) ++TRANS(vclo_w, LSX, gen_vv, gen_helper_vclo_w) ++TRANS(vclo_d, LSX, gen_vv, gen_helper_vclo_d) ++TRANS(vclz_b, LSX, gen_vv, gen_helper_vclz_b) ++TRANS(vclz_h, LSX, gen_vv, gen_helper_vclz_h) ++TRANS(vclz_w, LSX, gen_vv, gen_helper_vclz_w) ++TRANS(vclz_d, LSX, gen_vv, gen_helper_vclz_d) ++TRANS(xvclo_b, LASX, gen_xx, gen_helper_vclo_b) ++TRANS(xvclo_h, LASX, gen_xx, gen_helper_vclo_h) ++TRANS(xvclo_w, LASX, gen_xx, gen_helper_vclo_w) ++TRANS(xvclo_d, LASX, gen_xx, gen_helper_vclo_d) ++TRANS(xvclz_b, LASX, gen_xx, gen_helper_vclz_b) ++TRANS(xvclz_h, LASX, gen_xx, gen_helper_vclz_h) ++TRANS(xvclz_w, LASX, gen_xx, gen_helper_vclz_w) ++TRANS(xvclz_d, LASX, gen_xx, gen_helper_vclz_d) ++ ++TRANS(vpcnt_b, LSX, gen_vv, gen_helper_vpcnt_b) ++TRANS(vpcnt_h, LSX, gen_vv, gen_helper_vpcnt_h) ++TRANS(vpcnt_w, LSX, gen_vv, gen_helper_vpcnt_w) ++TRANS(vpcnt_d, LSX, gen_vv, gen_helper_vpcnt_d) ++TRANS(xvpcnt_b, LASX, gen_xx, gen_helper_vpcnt_b) ++TRANS(xvpcnt_h, LASX, gen_xx, gen_helper_vpcnt_h) ++TRANS(xvpcnt_w, LASX, gen_xx, gen_helper_vpcnt_w) ++TRANS(xvpcnt_d, LASX, gen_xx, gen_helper_vpcnt_d) ++ ++static void do_vbit(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, ++ void (*func)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) ++{ ++ TCGv_vec mask, lsh, t1, one; ++ ++ lsh = tcg_temp_new_vec_matching(t); ++ t1 = tcg_temp_new_vec_matching(t); ++ mask = tcg_constant_vec_matching(t, vece, (8 << vece) - 1); ++ one = tcg_constant_vec_matching(t, vece, 1); ++ ++ tcg_gen_and_vec(vece, lsh, b, mask); ++ tcg_gen_shlv_vec(vece, t1, one, lsh); ++ func(vece, t, a, t1); ++} ++ ++static void gen_vbitclr(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ do_vbit(vece, t, a, b, tcg_gen_andc_vec); ++} ++ ++static void gen_vbitset(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ do_vbit(vece, t, a, b, tcg_gen_or_vec); ++} ++ ++static void gen_vbitrev(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) ++{ ++ do_vbit(vece, t, a, b, tcg_gen_xor_vec); ++} ++ ++static void do_vbitclr(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shlv_vec, INDEX_op_andc_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vbitclr, ++ .fno = gen_helper_vbitclr_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vbitclr, ++ .fno = gen_helper_vbitclr_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vbitclr, ++ .fno = gen_helper_vbitclr_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vbitclr, ++ .fno = gen_helper_vbitclr_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vbitclr_b, LSX, gvec_vvv, MO_8, do_vbitclr) ++TRANS(vbitclr_h, LSX, gvec_vvv, MO_16, do_vbitclr) ++TRANS(vbitclr_w, LSX, gvec_vvv, MO_32, do_vbitclr) ++TRANS(vbitclr_d, LSX, gvec_vvv, MO_64, do_vbitclr) ++TRANS(xvbitclr_b, LASX, gvec_xxx, MO_8, do_vbitclr) ++TRANS(xvbitclr_h, LASX, gvec_xxx, MO_16, do_vbitclr) ++TRANS(xvbitclr_w, LASX, gvec_xxx, MO_32, do_vbitclr) ++TRANS(xvbitclr_d, LASX, gvec_xxx, MO_64, do_vbitclr) ++ ++static void do_vbiti(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm, ++ void (*func)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) ++{ ++ int lsh; ++ TCGv_vec t1, one; ++ ++ lsh = imm & ((8 << vece) -1); ++ t1 = tcg_temp_new_vec_matching(t); ++ one = tcg_constant_vec_matching(t, vece, 1); ++ ++ tcg_gen_shli_vec(vece, t1, one, lsh); ++ func(vece, t, a, t1); ++} ++ ++static void gen_vbitclri(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) ++{ ++ do_vbiti(vece, t, a, imm, tcg_gen_andc_vec); ++} ++ ++static void gen_vbitseti(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) ++{ ++ do_vbiti(vece, t, a, imm, tcg_gen_or_vec); ++} ++ ++static void gen_vbitrevi(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) ++{ ++ do_vbiti(vece, t, a, imm, tcg_gen_xor_vec); ++} ++ ++static void do_vbitclri(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ int64_t imm, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shli_vec, INDEX_op_andc_vec, 0 ++ }; ++ static const GVecGen2i op[4] = { ++ { ++ .fniv = gen_vbitclri, ++ .fnoi = gen_helper_vbitclri_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vbitclri, ++ .fnoi = gen_helper_vbitclri_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vbitclri, ++ .fnoi = gen_helper_vbitclri_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vbitclri, ++ .fnoi = gen_helper_vbitclri_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); ++} ++ ++TRANS(vbitclri_b, LSX, gvec_vv_i, MO_8, do_vbitclri) ++TRANS(vbitclri_h, LSX, gvec_vv_i, MO_16, do_vbitclri) ++TRANS(vbitclri_w, LSX, gvec_vv_i, MO_32, do_vbitclri) ++TRANS(vbitclri_d, LSX, gvec_vv_i, MO_64, do_vbitclri) ++TRANS(xvbitclri_b, LASX, gvec_xx_i, MO_8, do_vbitclri) ++TRANS(xvbitclri_h, LASX, gvec_xx_i, MO_16, do_vbitclri) ++TRANS(xvbitclri_w, LASX, gvec_xx_i, MO_32, do_vbitclri) ++TRANS(xvbitclri_d, LASX, gvec_xx_i, MO_64, do_vbitclri) ++ ++static void do_vbitset(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shlv_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vbitset, ++ .fno = gen_helper_vbitset_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vbitset, ++ .fno = gen_helper_vbitset_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vbitset, ++ .fno = gen_helper_vbitset_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vbitset, ++ .fno = gen_helper_vbitset_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vbitset_b, LSX, gvec_vvv, MO_8, do_vbitset) ++TRANS(vbitset_h, LSX, gvec_vvv, MO_16, do_vbitset) ++TRANS(vbitset_w, LSX, gvec_vvv, MO_32, do_vbitset) ++TRANS(vbitset_d, LSX, gvec_vvv, MO_64, do_vbitset) ++TRANS(xvbitset_b, LASX, gvec_xxx, MO_8, do_vbitset) ++TRANS(xvbitset_h, LASX, gvec_xxx, MO_16, do_vbitset) ++TRANS(xvbitset_w, LASX, gvec_xxx, MO_32, do_vbitset) ++TRANS(xvbitset_d, LASX, gvec_xxx, MO_64, do_vbitset) ++ ++static void do_vbitseti(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ int64_t imm, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shli_vec, 0 ++ }; ++ static const GVecGen2i op[4] = { ++ { ++ .fniv = gen_vbitseti, ++ .fnoi = gen_helper_vbitseti_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vbitseti, ++ .fnoi = gen_helper_vbitseti_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vbitseti, ++ .fnoi = gen_helper_vbitseti_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vbitseti, ++ .fnoi = gen_helper_vbitseti_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); ++} ++ ++TRANS(vbitseti_b, LSX, gvec_vv_i, MO_8, do_vbitseti) ++TRANS(vbitseti_h, LSX, gvec_vv_i, MO_16, do_vbitseti) ++TRANS(vbitseti_w, LSX, gvec_vv_i, MO_32, do_vbitseti) ++TRANS(vbitseti_d, LSX, gvec_vv_i, MO_64, do_vbitseti) ++TRANS(xvbitseti_b, LASX, gvec_xx_i, MO_8, do_vbitseti) ++TRANS(xvbitseti_h, LASX, gvec_xx_i, MO_16, do_vbitseti) ++TRANS(xvbitseti_w, LASX, gvec_xx_i, MO_32, do_vbitseti) ++TRANS(xvbitseti_d, LASX, gvec_xx_i, MO_64, do_vbitseti) ++ ++static void do_vbitrev(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shlv_vec, 0 ++ }; ++ static const GVecGen3 op[4] = { ++ { ++ .fniv = gen_vbitrev, ++ .fno = gen_helper_vbitrev_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vbitrev, ++ .fno = gen_helper_vbitrev_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vbitrev, ++ .fno = gen_helper_vbitrev_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vbitrev, ++ .fno = gen_helper_vbitrev_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); ++} ++ ++TRANS(vbitrev_b, LSX, gvec_vvv, MO_8, do_vbitrev) ++TRANS(vbitrev_h, LSX, gvec_vvv, MO_16, do_vbitrev) ++TRANS(vbitrev_w, LSX, gvec_vvv, MO_32, do_vbitrev) ++TRANS(vbitrev_d, LSX, gvec_vvv, MO_64, do_vbitrev) ++TRANS(xvbitrev_b, LASX, gvec_xxx, MO_8, do_vbitrev) ++TRANS(xvbitrev_h, LASX, gvec_xxx, MO_16, do_vbitrev) ++TRANS(xvbitrev_w, LASX, gvec_xxx, MO_32, do_vbitrev) ++TRANS(xvbitrev_d, LASX, gvec_xxx, MO_64, do_vbitrev) ++ ++static void do_vbitrevi(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, ++ int64_t imm, uint32_t oprsz, uint32_t maxsz) ++{ ++ static const TCGOpcode vecop_list[] = { ++ INDEX_op_shli_vec, 0 ++ }; ++ static const GVecGen2i op[4] = { ++ { ++ .fniv = gen_vbitrevi, ++ .fnoi = gen_helper_vbitrevi_b, ++ .opt_opc = vecop_list, ++ .vece = MO_8 ++ }, ++ { ++ .fniv = gen_vbitrevi, ++ .fnoi = gen_helper_vbitrevi_h, ++ .opt_opc = vecop_list, ++ .vece = MO_16 ++ }, ++ { ++ .fniv = gen_vbitrevi, ++ .fnoi = gen_helper_vbitrevi_w, ++ .opt_opc = vecop_list, ++ .vece = MO_32 ++ }, ++ { ++ .fniv = gen_vbitrevi, ++ .fnoi = gen_helper_vbitrevi_d, ++ .opt_opc = vecop_list, ++ .vece = MO_64 ++ }, ++ }; ++ ++ tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); ++} ++ ++TRANS(vbitrevi_b, LSX, gvec_vv_i, MO_8, do_vbitrevi) ++TRANS(vbitrevi_h, LSX, gvec_vv_i, MO_16, do_vbitrevi) ++TRANS(vbitrevi_w, LSX, gvec_vv_i, MO_32, do_vbitrevi) ++TRANS(vbitrevi_d, LSX, gvec_vv_i, MO_64, do_vbitrevi) ++TRANS(xvbitrevi_b, LASX, gvec_xx_i, MO_8, do_vbitrevi) ++TRANS(xvbitrevi_h, LASX, gvec_xx_i, MO_16, do_vbitrevi) ++TRANS(xvbitrevi_w, LASX, gvec_xx_i, MO_32, do_vbitrevi) ++TRANS(xvbitrevi_d, LASX, gvec_xx_i, MO_64, do_vbitrevi) ++ ++TRANS(vfrstp_b, LSX, gen_vvv, gen_helper_vfrstp_b) ++TRANS(vfrstp_h, LSX, gen_vvv, gen_helper_vfrstp_h) ++TRANS(vfrstpi_b, LSX, gen_vv_i, gen_helper_vfrstpi_b) ++TRANS(vfrstpi_h, LSX, gen_vv_i, gen_helper_vfrstpi_h) ++TRANS(xvfrstp_b, LASX, gen_xxx, gen_helper_vfrstp_b) ++TRANS(xvfrstp_h, LASX, gen_xxx, gen_helper_vfrstp_h) ++TRANS(xvfrstpi_b, LASX, gen_xx_i, gen_helper_vfrstpi_b) ++TRANS(xvfrstpi_h, LASX, gen_xx_i, gen_helper_vfrstpi_h) ++ ++TRANS(vfadd_s, LSX, gen_vvv_ptr, gen_helper_vfadd_s) ++TRANS(vfadd_d, LSX, gen_vvv_ptr, gen_helper_vfadd_d) ++TRANS(vfsub_s, LSX, gen_vvv_ptr, gen_helper_vfsub_s) ++TRANS(vfsub_d, LSX, gen_vvv_ptr, gen_helper_vfsub_d) ++TRANS(vfmul_s, LSX, gen_vvv_ptr, gen_helper_vfmul_s) ++TRANS(vfmul_d, LSX, gen_vvv_ptr, gen_helper_vfmul_d) ++TRANS(vfdiv_s, LSX, gen_vvv_ptr, gen_helper_vfdiv_s) ++TRANS(vfdiv_d, LSX, gen_vvv_ptr, gen_helper_vfdiv_d) ++TRANS(xvfadd_s, LASX, gen_xxx_ptr, gen_helper_vfadd_s) ++TRANS(xvfadd_d, LASX, gen_xxx_ptr, gen_helper_vfadd_d) ++TRANS(xvfsub_s, LASX, gen_xxx_ptr, gen_helper_vfsub_s) ++TRANS(xvfsub_d, LASX, gen_xxx_ptr, gen_helper_vfsub_d) ++TRANS(xvfmul_s, LASX, gen_xxx_ptr, gen_helper_vfmul_s) ++TRANS(xvfmul_d, LASX, gen_xxx_ptr, gen_helper_vfmul_d) ++TRANS(xvfdiv_s, LASX, gen_xxx_ptr, gen_helper_vfdiv_s) ++TRANS(xvfdiv_d, LASX, gen_xxx_ptr, gen_helper_vfdiv_d) ++ ++TRANS(vfmadd_s, LSX, gen_vvvv_ptr, gen_helper_vfmadd_s) ++TRANS(vfmadd_d, LSX, gen_vvvv_ptr, gen_helper_vfmadd_d) ++TRANS(vfmsub_s, LSX, gen_vvvv_ptr, gen_helper_vfmsub_s) ++TRANS(vfmsub_d, LSX, gen_vvvv_ptr, gen_helper_vfmsub_d) ++TRANS(vfnmadd_s, LSX, gen_vvvv_ptr, gen_helper_vfnmadd_s) ++TRANS(vfnmadd_d, LSX, gen_vvvv_ptr, gen_helper_vfnmadd_d) ++TRANS(vfnmsub_s, LSX, gen_vvvv_ptr, gen_helper_vfnmsub_s) ++TRANS(vfnmsub_d, LSX, gen_vvvv_ptr, gen_helper_vfnmsub_d) ++TRANS(xvfmadd_s, LASX, gen_xxxx_ptr, gen_helper_vfmadd_s) ++TRANS(xvfmadd_d, LASX, gen_xxxx_ptr, gen_helper_vfmadd_d) ++TRANS(xvfmsub_s, LASX, gen_xxxx_ptr, gen_helper_vfmsub_s) ++TRANS(xvfmsub_d, LASX, gen_xxxx_ptr, gen_helper_vfmsub_d) ++TRANS(xvfnmadd_s, LASX, gen_xxxx_ptr, gen_helper_vfnmadd_s) ++TRANS(xvfnmadd_d, LASX, gen_xxxx_ptr, gen_helper_vfnmadd_d) ++TRANS(xvfnmsub_s, LASX, gen_xxxx_ptr, gen_helper_vfnmsub_s) ++TRANS(xvfnmsub_d, LASX, gen_xxxx_ptr, gen_helper_vfnmsub_d) ++ ++TRANS(vfmax_s, LSX, gen_vvv_ptr, gen_helper_vfmax_s) ++TRANS(vfmax_d, LSX, gen_vvv_ptr, gen_helper_vfmax_d) ++TRANS(vfmin_s, LSX, gen_vvv_ptr, gen_helper_vfmin_s) ++TRANS(vfmin_d, LSX, gen_vvv_ptr, gen_helper_vfmin_d) ++TRANS(xvfmax_s, LASX, gen_xxx_ptr, gen_helper_vfmax_s) ++TRANS(xvfmax_d, LASX, gen_xxx_ptr, gen_helper_vfmax_d) ++TRANS(xvfmin_s, LASX, gen_xxx_ptr, gen_helper_vfmin_s) ++TRANS(xvfmin_d, LASX, gen_xxx_ptr, gen_helper_vfmin_d) ++ ++TRANS(vfmaxa_s, LSX, gen_vvv_ptr, gen_helper_vfmaxa_s) ++TRANS(vfmaxa_d, LSX, gen_vvv_ptr, gen_helper_vfmaxa_d) ++TRANS(vfmina_s, LSX, gen_vvv_ptr, gen_helper_vfmina_s) ++TRANS(vfmina_d, LSX, gen_vvv_ptr, gen_helper_vfmina_d) ++TRANS(xvfmaxa_s, LASX, gen_xxx_ptr, gen_helper_vfmaxa_s) ++TRANS(xvfmaxa_d, LASX, gen_xxx_ptr, gen_helper_vfmaxa_d) ++TRANS(xvfmina_s, LASX, gen_xxx_ptr, gen_helper_vfmina_s) ++TRANS(xvfmina_d, LASX, gen_xxx_ptr, gen_helper_vfmina_d) ++ ++TRANS(vflogb_s, LSX, gen_vv_ptr, gen_helper_vflogb_s) ++TRANS(vflogb_d, LSX, gen_vv_ptr, gen_helper_vflogb_d) ++TRANS(xvflogb_s, LASX, gen_xx_ptr, gen_helper_vflogb_s) ++TRANS(xvflogb_d, LASX, gen_xx_ptr, gen_helper_vflogb_d) ++ ++TRANS(vfclass_s, LSX, gen_vv_ptr, gen_helper_vfclass_s) ++TRANS(vfclass_d, LSX, gen_vv_ptr, gen_helper_vfclass_d) ++TRANS(xvfclass_s, LASX, gen_xx_ptr, gen_helper_vfclass_s) ++TRANS(xvfclass_d, LASX, gen_xx_ptr, gen_helper_vfclass_d) ++ ++TRANS(vfsqrt_s, LSX, gen_vv_ptr, gen_helper_vfsqrt_s) ++TRANS(vfsqrt_d, LSX, gen_vv_ptr, gen_helper_vfsqrt_d) ++TRANS(vfrecip_s, LSX, gen_vv_ptr, gen_helper_vfrecip_s) ++TRANS(vfrecip_d, LSX, gen_vv_ptr, gen_helper_vfrecip_d) ++TRANS(vfrsqrt_s, LSX, gen_vv_ptr, gen_helper_vfrsqrt_s) ++TRANS(vfrsqrt_d, LSX, gen_vv_ptr, gen_helper_vfrsqrt_d) ++TRANS(xvfsqrt_s, LASX, gen_xx_ptr, gen_helper_vfsqrt_s) ++TRANS(xvfsqrt_d, LASX, gen_xx_ptr, gen_helper_vfsqrt_d) ++TRANS(xvfrecip_s, LASX, gen_xx_ptr, gen_helper_vfrecip_s) ++TRANS(xvfrecip_d, LASX, gen_xx_ptr, gen_helper_vfrecip_d) ++TRANS(xvfrsqrt_s, LASX, gen_xx_ptr, gen_helper_vfrsqrt_s) ++TRANS(xvfrsqrt_d, LASX, gen_xx_ptr, gen_helper_vfrsqrt_d) ++ ++TRANS(vfcvtl_s_h, LSX, gen_vv_ptr, gen_helper_vfcvtl_s_h) ++TRANS(vfcvth_s_h, LSX, gen_vv_ptr, gen_helper_vfcvth_s_h) ++TRANS(vfcvtl_d_s, LSX, gen_vv_ptr, gen_helper_vfcvtl_d_s) ++TRANS(vfcvth_d_s, LSX, gen_vv_ptr, gen_helper_vfcvth_d_s) ++TRANS(vfcvt_h_s, LSX, gen_vvv_ptr, gen_helper_vfcvt_h_s) ++TRANS(vfcvt_s_d, LSX, gen_vvv_ptr, gen_helper_vfcvt_s_d) ++TRANS(xvfcvtl_s_h, LASX, gen_xx_ptr, gen_helper_vfcvtl_s_h) ++TRANS(xvfcvth_s_h, LASX, gen_xx_ptr, gen_helper_vfcvth_s_h) ++TRANS(xvfcvtl_d_s, LASX, gen_xx_ptr, gen_helper_vfcvtl_d_s) ++TRANS(xvfcvth_d_s, LASX, gen_xx_ptr, gen_helper_vfcvth_d_s) ++TRANS(xvfcvt_h_s, LASX, gen_xxx_ptr, gen_helper_vfcvt_h_s) ++TRANS(xvfcvt_s_d, LASX, gen_xxx_ptr, gen_helper_vfcvt_s_d) ++ ++TRANS(vfrintrne_s, LSX, gen_vv_ptr, gen_helper_vfrintrne_s) ++TRANS(vfrintrne_d, LSX, gen_vv_ptr, gen_helper_vfrintrne_d) ++TRANS(vfrintrz_s, LSX, gen_vv_ptr, gen_helper_vfrintrz_s) ++TRANS(vfrintrz_d, LSX, gen_vv_ptr, gen_helper_vfrintrz_d) ++TRANS(vfrintrp_s, LSX, gen_vv_ptr, gen_helper_vfrintrp_s) ++TRANS(vfrintrp_d, LSX, gen_vv_ptr, gen_helper_vfrintrp_d) ++TRANS(vfrintrm_s, LSX, gen_vv_ptr, gen_helper_vfrintrm_s) ++TRANS(vfrintrm_d, LSX, gen_vv_ptr, gen_helper_vfrintrm_d) ++TRANS(vfrint_s, LSX, gen_vv_ptr, gen_helper_vfrint_s) ++TRANS(vfrint_d, LSX, gen_vv_ptr, gen_helper_vfrint_d) ++TRANS(xvfrintrne_s, LASX, gen_xx_ptr, gen_helper_vfrintrne_s) ++TRANS(xvfrintrne_d, LASX, gen_xx_ptr, gen_helper_vfrintrne_d) ++TRANS(xvfrintrz_s, LASX, gen_xx_ptr, gen_helper_vfrintrz_s) ++TRANS(xvfrintrz_d, LASX, gen_xx_ptr, gen_helper_vfrintrz_d) ++TRANS(xvfrintrp_s, LASX, gen_xx_ptr, gen_helper_vfrintrp_s) ++TRANS(xvfrintrp_d, LASX, gen_xx_ptr, gen_helper_vfrintrp_d) ++TRANS(xvfrintrm_s, LASX, gen_xx_ptr, gen_helper_vfrintrm_s) ++TRANS(xvfrintrm_d, LASX, gen_xx_ptr, gen_helper_vfrintrm_d) ++TRANS(xvfrint_s, LASX, gen_xx_ptr, gen_helper_vfrint_s) ++TRANS(xvfrint_d, LASX, gen_xx_ptr, gen_helper_vfrint_d) ++ ++TRANS(vftintrne_w_s, LSX, gen_vv_ptr, gen_helper_vftintrne_w_s) ++TRANS(vftintrne_l_d, LSX, gen_vv_ptr, gen_helper_vftintrne_l_d) ++TRANS(vftintrz_w_s, LSX, gen_vv_ptr, gen_helper_vftintrz_w_s) ++TRANS(vftintrz_l_d, LSX, gen_vv_ptr, gen_helper_vftintrz_l_d) ++TRANS(vftintrp_w_s, LSX, gen_vv_ptr, gen_helper_vftintrp_w_s) ++TRANS(vftintrp_l_d, LSX, gen_vv_ptr, gen_helper_vftintrp_l_d) ++TRANS(vftintrm_w_s, LSX, gen_vv_ptr, gen_helper_vftintrm_w_s) ++TRANS(vftintrm_l_d, LSX, gen_vv_ptr, gen_helper_vftintrm_l_d) ++TRANS(vftint_w_s, LSX, gen_vv_ptr, gen_helper_vftint_w_s) ++TRANS(vftint_l_d, LSX, gen_vv_ptr, gen_helper_vftint_l_d) ++TRANS(vftintrz_wu_s, LSX, gen_vv_ptr, gen_helper_vftintrz_wu_s) ++TRANS(vftintrz_lu_d, LSX, gen_vv_ptr, gen_helper_vftintrz_lu_d) ++TRANS(vftint_wu_s, LSX, gen_vv_ptr, gen_helper_vftint_wu_s) ++TRANS(vftint_lu_d, LSX, gen_vv_ptr, gen_helper_vftint_lu_d) ++TRANS(vftintrne_w_d, LSX, gen_vvv_ptr, gen_helper_vftintrne_w_d) ++TRANS(vftintrz_w_d, LSX, gen_vvv_ptr, gen_helper_vftintrz_w_d) ++TRANS(vftintrp_w_d, LSX, gen_vvv_ptr, gen_helper_vftintrp_w_d) ++TRANS(vftintrm_w_d, LSX, gen_vvv_ptr, gen_helper_vftintrm_w_d) ++TRANS(vftint_w_d, LSX, gen_vvv_ptr, gen_helper_vftint_w_d) ++TRANS(vftintrnel_l_s, LSX, gen_vv_ptr, gen_helper_vftintrnel_l_s) ++TRANS(vftintrneh_l_s, LSX, gen_vv_ptr, gen_helper_vftintrneh_l_s) ++TRANS(vftintrzl_l_s, LSX, gen_vv_ptr, gen_helper_vftintrzl_l_s) ++TRANS(vftintrzh_l_s, LSX, gen_vv_ptr, gen_helper_vftintrzh_l_s) ++TRANS(vftintrpl_l_s, LSX, gen_vv_ptr, gen_helper_vftintrpl_l_s) ++TRANS(vftintrph_l_s, LSX, gen_vv_ptr, gen_helper_vftintrph_l_s) ++TRANS(vftintrml_l_s, LSX, gen_vv_ptr, gen_helper_vftintrml_l_s) ++TRANS(vftintrmh_l_s, LSX, gen_vv_ptr, gen_helper_vftintrmh_l_s) ++TRANS(vftintl_l_s, LSX, gen_vv_ptr, gen_helper_vftintl_l_s) ++TRANS(vftinth_l_s, LSX, gen_vv_ptr, gen_helper_vftinth_l_s) ++TRANS(xvftintrne_w_s, LASX, gen_xx_ptr, gen_helper_vftintrne_w_s) ++TRANS(xvftintrne_l_d, LASX, gen_xx_ptr, gen_helper_vftintrne_l_d) ++TRANS(xvftintrz_w_s, LASX, gen_xx_ptr, gen_helper_vftintrz_w_s) ++TRANS(xvftintrz_l_d, LASX, gen_xx_ptr, gen_helper_vftintrz_l_d) ++TRANS(xvftintrp_w_s, LASX, gen_xx_ptr, gen_helper_vftintrp_w_s) ++TRANS(xvftintrp_l_d, LASX, gen_xx_ptr, gen_helper_vftintrp_l_d) ++TRANS(xvftintrm_w_s, LASX, gen_xx_ptr, gen_helper_vftintrm_w_s) ++TRANS(xvftintrm_l_d, LASX, gen_xx_ptr, gen_helper_vftintrm_l_d) ++TRANS(xvftint_w_s, LASX, gen_xx_ptr, gen_helper_vftint_w_s) ++TRANS(xvftint_l_d, LASX, gen_xx_ptr, gen_helper_vftint_l_d) ++TRANS(xvftintrz_wu_s, LASX, gen_xx_ptr, gen_helper_vftintrz_wu_s) ++TRANS(xvftintrz_lu_d, LASX, gen_xx_ptr, gen_helper_vftintrz_lu_d) ++TRANS(xvftint_wu_s, LASX, gen_xx_ptr, gen_helper_vftint_wu_s) ++TRANS(xvftint_lu_d, LASX, gen_xx_ptr, gen_helper_vftint_lu_d) ++TRANS(xvftintrne_w_d, LASX, gen_xxx_ptr, gen_helper_vftintrne_w_d) ++TRANS(xvftintrz_w_d, LASX, gen_xxx_ptr, gen_helper_vftintrz_w_d) ++TRANS(xvftintrp_w_d, LASX, gen_xxx_ptr, gen_helper_vftintrp_w_d) ++TRANS(xvftintrm_w_d, LASX, gen_xxx_ptr, gen_helper_vftintrm_w_d) ++TRANS(xvftint_w_d, LASX, gen_xxx_ptr, gen_helper_vftint_w_d) ++TRANS(xvftintrnel_l_s, LASX, gen_xx_ptr, gen_helper_vftintrnel_l_s) ++TRANS(xvftintrneh_l_s, LASX, gen_xx_ptr, gen_helper_vftintrneh_l_s) ++TRANS(xvftintrzl_l_s, LASX, gen_xx_ptr, gen_helper_vftintrzl_l_s) ++TRANS(xvftintrzh_l_s, LASX, gen_xx_ptr, gen_helper_vftintrzh_l_s) ++TRANS(xvftintrpl_l_s, LASX, gen_xx_ptr, gen_helper_vftintrpl_l_s) ++TRANS(xvftintrph_l_s, LASX, gen_xx_ptr, gen_helper_vftintrph_l_s) ++TRANS(xvftintrml_l_s, LASX, gen_xx_ptr, gen_helper_vftintrml_l_s) ++TRANS(xvftintrmh_l_s, LASX, gen_xx_ptr, gen_helper_vftintrmh_l_s) ++TRANS(xvftintl_l_s, LASX, gen_xx_ptr, gen_helper_vftintl_l_s) ++TRANS(xvftinth_l_s, LASX, gen_xx_ptr, gen_helper_vftinth_l_s) ++ ++TRANS(vffint_s_w, LSX, gen_vv_ptr, gen_helper_vffint_s_w) ++TRANS(vffint_d_l, LSX, gen_vv_ptr, gen_helper_vffint_d_l) ++TRANS(vffint_s_wu, LSX, gen_vv_ptr, gen_helper_vffint_s_wu) ++TRANS(vffint_d_lu, LSX, gen_vv_ptr, gen_helper_vffint_d_lu) ++TRANS(vffintl_d_w, LSX, gen_vv_ptr, gen_helper_vffintl_d_w) ++TRANS(vffinth_d_w, LSX, gen_vv_ptr, gen_helper_vffinth_d_w) ++TRANS(vffint_s_l, LSX, gen_vvv_ptr, gen_helper_vffint_s_l) ++TRANS(xvffint_s_w, LASX, gen_xx_ptr, gen_helper_vffint_s_w) ++TRANS(xvffint_d_l, LASX, gen_xx_ptr, gen_helper_vffint_d_l) ++TRANS(xvffint_s_wu, LASX, gen_xx_ptr, gen_helper_vffint_s_wu) ++TRANS(xvffint_d_lu, LASX, gen_xx_ptr, gen_helper_vffint_d_lu) ++TRANS(xvffintl_d_w, LASX, gen_xx_ptr, gen_helper_vffintl_d_w) ++TRANS(xvffinth_d_w, LASX, gen_xx_ptr, gen_helper_vffinth_d_w) ++TRANS(xvffint_s_l, LASX, gen_xxx_ptr, gen_helper_vffint_s_l) ++ ++static bool do_cmp_vl(DisasContext *ctx, arg_vvv *a, ++ uint32_t oprsz, MemOp mop, TCGCond cond) ++{ ++ uint32_t vd_ofs, vj_ofs, vk_ofs; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ vd_ofs = vec_full_offset(a->vd); ++ vj_ofs = vec_full_offset(a->vj); ++ vk_ofs = vec_full_offset(a->vk); ++ ++ tcg_gen_gvec_cmp(cond, mop, vd_ofs, vj_ofs, vk_ofs, oprsz, ctx->vl / 8); ++ return true; ++} ++ ++static bool do_cmp(DisasContext *ctx, arg_vvv *a, ++ MemOp mop, TCGCond cond) ++{ ++ return do_cmp_vl(ctx, a, 16, mop, cond); ++} ++ ++static bool do_xcmp(DisasContext *ctx, arg_vvv *a, ++ MemOp mop, TCGCond cond) ++{ ++ return do_cmp_vl(ctx, a, 32, mop, cond); ++} ++ ++static bool do_cmpi_vl(DisasContext *ctx, arg_vv_i *a, ++ uint32_t oprsz, MemOp mop, TCGCond cond) ++{ ++ uint32_t vd_ofs, vj_ofs; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ vd_ofs = vec_full_offset(a->vd); ++ vj_ofs = vec_full_offset(a->vj); ++ ++ tcg_gen_gvec_cmpi(cond, mop, vd_ofs, vj_ofs, a->imm, oprsz, ctx->vl / 8); ++ return true; ++} ++ ++static bool do_cmpi(DisasContext *ctx, arg_vv_i *a, ++ MemOp mop, TCGCond cond) ++{ ++ return do_cmpi_vl(ctx, a, 16, mop, cond); ++} ++ ++static bool do_xcmpi(DisasContext *ctx, arg_vv_i *a, ++ MemOp mop, TCGCond cond) ++{ ++ return do_cmpi_vl(ctx, a, 32, mop, cond); ++} ++ ++TRANS(vseq_b, LSX, do_cmp, MO_8, TCG_COND_EQ) ++TRANS(vseq_h, LSX, do_cmp, MO_16, TCG_COND_EQ) ++TRANS(vseq_w, LSX, do_cmp, MO_32, TCG_COND_EQ) ++TRANS(vseq_d, LSX, do_cmp, MO_64, TCG_COND_EQ) ++TRANS(vseqi_b, LSX, do_cmpi, MO_8, TCG_COND_EQ) ++TRANS(vseqi_h, LSX, do_cmpi, MO_16, TCG_COND_EQ) ++TRANS(vseqi_w, LSX, do_cmpi, MO_32, TCG_COND_EQ) ++TRANS(vseqi_d, LSX, do_cmpi, MO_64, TCG_COND_EQ) ++TRANS(xvseq_b, LASX, do_xcmp, MO_8, TCG_COND_EQ) ++TRANS(xvseq_h, LASX, do_xcmp, MO_16, TCG_COND_EQ) ++TRANS(xvseq_w, LASX, do_xcmp, MO_32, TCG_COND_EQ) ++TRANS(xvseq_d, LASX, do_xcmp, MO_64, TCG_COND_EQ) ++TRANS(xvseqi_b, LASX, do_xcmpi, MO_8, TCG_COND_EQ) ++TRANS(xvseqi_h, LASX, do_xcmpi, MO_16, TCG_COND_EQ) ++TRANS(xvseqi_w, LASX, do_xcmpi, MO_32, TCG_COND_EQ) ++TRANS(xvseqi_d, LASX, do_xcmpi, MO_64, TCG_COND_EQ) ++ ++TRANS(vsle_b, LSX, do_cmp, MO_8, TCG_COND_LE) ++TRANS(vsle_h, LSX, do_cmp, MO_16, TCG_COND_LE) ++TRANS(vsle_w, LSX, do_cmp, MO_32, TCG_COND_LE) ++TRANS(vsle_d, LSX, do_cmp, MO_64, TCG_COND_LE) ++TRANS(vslei_b, LSX, do_cmpi, MO_8, TCG_COND_LE) ++TRANS(vslei_h, LSX, do_cmpi, MO_16, TCG_COND_LE) ++TRANS(vslei_w, LSX, do_cmpi, MO_32, TCG_COND_LE) ++TRANS(vslei_d, LSX, do_cmpi, MO_64, TCG_COND_LE) ++TRANS(vsle_bu, LSX, do_cmp, MO_8, TCG_COND_LEU) ++TRANS(vsle_hu, LSX, do_cmp, MO_16, TCG_COND_LEU) ++TRANS(vsle_wu, LSX, do_cmp, MO_32, TCG_COND_LEU) ++TRANS(vsle_du, LSX, do_cmp, MO_64, TCG_COND_LEU) ++TRANS(vslei_bu, LSX, do_cmpi, MO_8, TCG_COND_LEU) ++TRANS(vslei_hu, LSX, do_cmpi, MO_16, TCG_COND_LEU) ++TRANS(vslei_wu, LSX, do_cmpi, MO_32, TCG_COND_LEU) ++TRANS(vslei_du, LSX, do_cmpi, MO_64, TCG_COND_LEU) ++TRANS(xvsle_b, LASX, do_xcmp, MO_8, TCG_COND_LE) ++TRANS(xvsle_h, LASX, do_xcmp, MO_16, TCG_COND_LE) ++TRANS(xvsle_w, LASX, do_xcmp, MO_32, TCG_COND_LE) ++TRANS(xvsle_d, LASX, do_xcmp, MO_64, TCG_COND_LE) ++TRANS(xvslei_b, LASX, do_xcmpi, MO_8, TCG_COND_LE) ++TRANS(xvslei_h, LASX, do_xcmpi, MO_16, TCG_COND_LE) ++TRANS(xvslei_w, LASX, do_xcmpi, MO_32, TCG_COND_LE) ++TRANS(xvslei_d, LASX, do_xcmpi, MO_64, TCG_COND_LE) ++TRANS(xvsle_bu, LASX, do_xcmp, MO_8, TCG_COND_LEU) ++TRANS(xvsle_hu, LASX, do_xcmp, MO_16, TCG_COND_LEU) ++TRANS(xvsle_wu, LASX, do_xcmp, MO_32, TCG_COND_LEU) ++TRANS(xvsle_du, LASX, do_xcmp, MO_64, TCG_COND_LEU) ++TRANS(xvslei_bu, LASX, do_xcmpi, MO_8, TCG_COND_LEU) ++TRANS(xvslei_hu, LASX, do_xcmpi, MO_16, TCG_COND_LEU) ++TRANS(xvslei_wu, LASX, do_xcmpi, MO_32, TCG_COND_LEU) ++TRANS(xvslei_du, LASX, do_xcmpi, MO_64, TCG_COND_LEU) ++ ++TRANS(vslt_b, LSX, do_cmp, MO_8, TCG_COND_LT) ++TRANS(vslt_h, LSX, do_cmp, MO_16, TCG_COND_LT) ++TRANS(vslt_w, LSX, do_cmp, MO_32, TCG_COND_LT) ++TRANS(vslt_d, LSX, do_cmp, MO_64, TCG_COND_LT) ++TRANS(vslti_b, LSX, do_cmpi, MO_8, TCG_COND_LT) ++TRANS(vslti_h, LSX, do_cmpi, MO_16, TCG_COND_LT) ++TRANS(vslti_w, LSX, do_cmpi, MO_32, TCG_COND_LT) ++TRANS(vslti_d, LSX, do_cmpi, MO_64, TCG_COND_LT) ++TRANS(vslt_bu, LSX, do_cmp, MO_8, TCG_COND_LTU) ++TRANS(vslt_hu, LSX, do_cmp, MO_16, TCG_COND_LTU) ++TRANS(vslt_wu, LSX, do_cmp, MO_32, TCG_COND_LTU) ++TRANS(vslt_du, LSX, do_cmp, MO_64, TCG_COND_LTU) ++TRANS(vslti_bu, LSX, do_cmpi, MO_8, TCG_COND_LTU) ++TRANS(vslti_hu, LSX, do_cmpi, MO_16, TCG_COND_LTU) ++TRANS(vslti_wu, LSX, do_cmpi, MO_32, TCG_COND_LTU) ++TRANS(vslti_du, LSX, do_cmpi, MO_64, TCG_COND_LTU) ++TRANS(xvslt_b, LASX, do_xcmp, MO_8, TCG_COND_LT) ++TRANS(xvslt_h, LASX, do_xcmp, MO_16, TCG_COND_LT) ++TRANS(xvslt_w, LASX, do_xcmp, MO_32, TCG_COND_LT) ++TRANS(xvslt_d, LASX, do_xcmp, MO_64, TCG_COND_LT) ++TRANS(xvslti_b, LASX, do_xcmpi, MO_8, TCG_COND_LT) ++TRANS(xvslti_h, LASX, do_xcmpi, MO_16, TCG_COND_LT) ++TRANS(xvslti_w, LASX, do_xcmpi, MO_32, TCG_COND_LT) ++TRANS(xvslti_d, LASX, do_xcmpi, MO_64, TCG_COND_LT) ++TRANS(xvslt_bu, LASX, do_xcmp, MO_8, TCG_COND_LTU) ++TRANS(xvslt_hu, LASX, do_xcmp, MO_16, TCG_COND_LTU) ++TRANS(xvslt_wu, LASX, do_xcmp, MO_32, TCG_COND_LTU) ++TRANS(xvslt_du, LASX, do_xcmp, MO_64, TCG_COND_LTU) ++TRANS(xvslti_bu, LASX, do_xcmpi, MO_8, TCG_COND_LTU) ++TRANS(xvslti_hu, LASX, do_xcmpi, MO_16, TCG_COND_LTU) ++TRANS(xvslti_wu, LASX, do_xcmpi, MO_32, TCG_COND_LTU) ++TRANS(xvslti_du, LASX, do_xcmpi, MO_64, TCG_COND_LTU) ++ ++static bool do_vfcmp_cond_s(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz) ++{ ++ uint32_t flags; ++ void (*fn)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32); ++ TCGv_i32 vd = tcg_constant_i32(a->vd); ++ TCGv_i32 vj = tcg_constant_i32(a->vj); ++ TCGv_i32 vk = tcg_constant_i32(a->vk); ++ TCGv_i32 oprsz = tcg_constant_i32(sz); ++ ++ if (!check_vec(ctx, sz)) { ++ return true; ++ } ++ ++ fn = (a->fcond & 1 ? gen_helper_vfcmp_s_s : gen_helper_vfcmp_c_s); ++ flags = get_fcmp_flags(a->fcond >> 1); ++ fn(tcg_env, oprsz, vd, vj, vk, tcg_constant_i32(flags)); ++ ++ return true; ++} ++ ++static bool do_vfcmp_cond_d(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz) ++{ ++ uint32_t flags; ++ void (*fn)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32); ++ TCGv_i32 vd = tcg_constant_i32(a->vd); ++ TCGv_i32 vj = tcg_constant_i32(a->vj); ++ TCGv_i32 vk = tcg_constant_i32(a->vk); ++ TCGv_i32 oprsz = tcg_constant_i32(sz); ++ ++ if (!check_vec(ctx, sz)) { ++ return true; ++ } ++ ++ fn = (a->fcond & 1 ? gen_helper_vfcmp_s_d : gen_helper_vfcmp_c_d); ++ flags = get_fcmp_flags(a->fcond >> 1); ++ fn(tcg_env, oprsz, vd, vj, vk, tcg_constant_i32(flags)); ++ ++ return true; ++} ++ ++TRANS(vfcmp_cond_s, LSX, do_vfcmp_cond_s, 16) ++TRANS(vfcmp_cond_d, LSX, do_vfcmp_cond_d, 16) ++TRANS(xvfcmp_cond_s, LASX, do_vfcmp_cond_s, 32) ++TRANS(xvfcmp_cond_d, LASX, do_vfcmp_cond_d, 32) ++ ++static bool do_vbitsel_v(DisasContext *ctx, arg_vvvv *a, uint32_t oprsz) ++{ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_bitsel(MO_64, vec_full_offset(a->vd), vec_full_offset(a->va), ++ vec_full_offset(a->vk), vec_full_offset(a->vj), ++ oprsz, ctx->vl / 8); ++ return true; ++} ++ ++TRANS(vbitsel_v, LSX, do_vbitsel_v, 16) ++TRANS(xvbitsel_v, LASX, do_vbitsel_v, 32) ++ ++static void gen_vbitseli(unsigned vece, TCGv_vec a, TCGv_vec b, int64_t imm) ++{ ++ tcg_gen_bitsel_vec(vece, a, a, tcg_constant_vec_matching(a, vece, imm), b); ++} ++ ++static bool do_vbitseli_b(DisasContext *ctx, arg_vv_i *a, uint32_t oprsz) ++{ ++ static const GVecGen2i op = { ++ .fniv = gen_vbitseli, ++ .fnoi = gen_helper_vbitseli_b, ++ .vece = MO_8, ++ .load_dest = true ++ }; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_2i(vec_full_offset(a->vd), vec_full_offset(a->vj), ++ oprsz, ctx->vl / 8, a->imm , &op); ++ return true; ++} ++ ++TRANS(vbitseli_b, LSX, do_vbitseli_b, 16) ++TRANS(xvbitseli_b, LASX, do_vbitseli_b, 32) ++ ++#define VSET(NAME, COND) \ ++static bool trans_## NAME (DisasContext *ctx, arg_cv *a) \ ++{ \ ++ TCGv_i64 t1, al, ah; \ ++ \ ++ al = tcg_temp_new_i64(); \ ++ ah = tcg_temp_new_i64(); \ ++ t1 = tcg_temp_new_i64(); \ ++ \ ++ get_vreg64(ah, a->vj, 1); \ ++ get_vreg64(al, a->vj, 0); \ ++ \ ++ if (!avail_LSX(ctx)) { \ ++ return false; \ ++ } \ ++ \ ++ if (!check_vec(ctx, 16)) { \ ++ return true; \ ++ } \ ++ \ ++ tcg_gen_or_i64(t1, al, ah); \ ++ tcg_gen_setcondi_i64(COND, t1, t1, 0); \ ++ tcg_gen_st8_tl(t1, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); \ ++ \ ++ return true; \ ++} ++ ++VSET(vseteqz_v, TCG_COND_EQ) ++VSET(vsetnez_v, TCG_COND_NE) ++ ++TRANS(vsetanyeqz_b, LSX, gen_cv, gen_helper_vsetanyeqz_b) ++TRANS(vsetanyeqz_h, LSX, gen_cv, gen_helper_vsetanyeqz_h) ++TRANS(vsetanyeqz_w, LSX, gen_cv, gen_helper_vsetanyeqz_w) ++TRANS(vsetanyeqz_d, LSX, gen_cv, gen_helper_vsetanyeqz_d) ++TRANS(vsetallnez_b, LSX, gen_cv, gen_helper_vsetallnez_b) ++TRANS(vsetallnez_h, LSX, gen_cv, gen_helper_vsetallnez_h) ++TRANS(vsetallnez_w, LSX, gen_cv, gen_helper_vsetallnez_w) ++TRANS(vsetallnez_d, LSX, gen_cv, gen_helper_vsetallnez_d) ++ ++#define XVSET(NAME, COND) \ ++static bool trans_## NAME(DisasContext *ctx, arg_cv * a) \ ++{ \ ++ TCGv_i64 t1, t2, d[4]; \ ++ \ ++ d[0] = tcg_temp_new_i64(); \ ++ d[1] = tcg_temp_new_i64(); \ ++ d[2] = tcg_temp_new_i64(); \ ++ d[3] = tcg_temp_new_i64(); \ ++ t1 = tcg_temp_new_i64(); \ ++ t2 = tcg_temp_new_i64(); \ ++ \ ++ get_vreg64(d[0], a->vj, 0); \ ++ get_vreg64(d[1], a->vj, 1); \ ++ get_vreg64(d[2], a->vj, 2); \ ++ get_vreg64(d[3], a->vj, 3); \ ++ \ ++ if (!avail_LASX(ctx)) { \ ++ return false; \ ++ } \ ++ \ ++ if (!check_vec(ctx, 32)) { \ ++ return true; \ ++ } \ ++ \ ++ tcg_gen_or_i64(t1, d[0], d[1]); \ ++ tcg_gen_or_i64(t2, d[2], d[3]); \ ++ tcg_gen_or_i64(t1, t2, t1); \ ++ tcg_gen_setcondi_i64(COND, t1, t1, 0); \ ++ tcg_gen_st8_tl(t1, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); \ ++ \ ++ return true; \ ++} ++ ++XVSET(xvseteqz_v, TCG_COND_EQ) ++XVSET(xvsetnez_v, TCG_COND_NE) ++ ++TRANS(xvsetanyeqz_b, LASX, gen_cx, gen_helper_vsetanyeqz_b) ++TRANS(xvsetanyeqz_h, LASX, gen_cx, gen_helper_vsetanyeqz_h) ++TRANS(xvsetanyeqz_w, LASX, gen_cx, gen_helper_vsetanyeqz_w) ++TRANS(xvsetanyeqz_d, LASX, gen_cx, gen_helper_vsetanyeqz_d) ++TRANS(xvsetallnez_b, LASX, gen_cx, gen_helper_vsetallnez_b) ++TRANS(xvsetallnez_h, LASX, gen_cx, gen_helper_vsetallnez_h) ++TRANS(xvsetallnez_w, LASX, gen_cx, gen_helper_vsetallnez_w) ++TRANS(xvsetallnez_d, LASX, gen_cx, gen_helper_vsetallnez_d) ++ ++static bool gen_g2v_vl(DisasContext *ctx, arg_vr_i *a, uint32_t oprsz, MemOp mop, ++ void (*func)(TCGv, TCGv_ptr, tcg_target_long)) ++{ ++ TCGv src = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ func(src, tcg_env, vec_reg_offset(a->vd, a->imm, mop)); ++ ++ return true; ++} ++ ++static bool gen_g2v(DisasContext *ctx, arg_vr_i *a, MemOp mop, ++ void (*func)(TCGv, TCGv_ptr, tcg_target_long)) ++{ ++ return gen_g2v_vl(ctx, a, 16, mop, func); ++} ++ ++static bool gen_g2x(DisasContext *ctx, arg_vr_i *a, MemOp mop, ++ void (*func)(TCGv, TCGv_ptr, tcg_target_long)) ++{ ++ return gen_g2v_vl(ctx, a, 32, mop, func); ++} ++ ++TRANS(vinsgr2vr_b, LSX, gen_g2v, MO_8, tcg_gen_st8_i64) ++TRANS(vinsgr2vr_h, LSX, gen_g2v, MO_16, tcg_gen_st16_i64) ++TRANS(vinsgr2vr_w, LSX, gen_g2v, MO_32, tcg_gen_st32_i64) ++TRANS(vinsgr2vr_d, LSX, gen_g2v, MO_64, tcg_gen_st_i64) ++TRANS(xvinsgr2vr_w, LASX, gen_g2x, MO_32, tcg_gen_st32_i64) ++TRANS(xvinsgr2vr_d, LASX, gen_g2x, MO_64, tcg_gen_st_i64) ++ ++static bool gen_v2g_vl(DisasContext *ctx, arg_rv_i *a, uint32_t oprsz, MemOp mop, ++ void (*func)(TCGv, TCGv_ptr, tcg_target_long)) ++{ ++ TCGv dst = gpr_dst(ctx, a->rd, EXT_NONE); ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ func(dst, tcg_env, vec_reg_offset(a->vj, a->imm, mop)); ++ ++ return true; ++} ++ ++static bool gen_v2g(DisasContext *ctx, arg_rv_i *a, MemOp mop, ++ void (*func)(TCGv, TCGv_ptr, tcg_target_long)) ++{ ++ return gen_v2g_vl(ctx, a, 16, mop, func); ++} ++ ++static bool gen_x2g(DisasContext *ctx, arg_rv_i *a, MemOp mop, ++ void (*func)(TCGv, TCGv_ptr, tcg_target_long)) ++{ ++ return gen_v2g_vl(ctx, a, 32, mop, func); ++} ++ ++TRANS(vpickve2gr_b, LSX, gen_v2g, MO_8, tcg_gen_ld8s_i64) ++TRANS(vpickve2gr_h, LSX, gen_v2g, MO_16, tcg_gen_ld16s_i64) ++TRANS(vpickve2gr_w, LSX, gen_v2g, MO_32, tcg_gen_ld32s_i64) ++TRANS(vpickve2gr_d, LSX, gen_v2g, MO_64, tcg_gen_ld_i64) ++TRANS(vpickve2gr_bu, LSX, gen_v2g, MO_8, tcg_gen_ld8u_i64) ++TRANS(vpickve2gr_hu, LSX, gen_v2g, MO_16, tcg_gen_ld16u_i64) ++TRANS(vpickve2gr_wu, LSX, gen_v2g, MO_32, tcg_gen_ld32u_i64) ++TRANS(vpickve2gr_du, LSX, gen_v2g, MO_64, tcg_gen_ld_i64) ++TRANS(xvpickve2gr_w, LASX, gen_x2g, MO_32, tcg_gen_ld32s_i64) ++TRANS(xvpickve2gr_d, LASX, gen_x2g, MO_64, tcg_gen_ld_i64) ++TRANS(xvpickve2gr_wu, LASX, gen_x2g, MO_32, tcg_gen_ld32u_i64) ++TRANS(xvpickve2gr_du, LASX, gen_x2g, MO_64, tcg_gen_ld_i64) ++ ++static bool gvec_dup_vl(DisasContext *ctx, arg_vr *a, ++ uint32_t oprsz, MemOp mop) ++{ ++ TCGv src = gpr_src(ctx, a->rj, EXT_NONE); ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_dup_i64(mop, vec_full_offset(a->vd), ++ oprsz, ctx->vl/8, src); ++ return true; ++} ++ ++static bool gvec_dup(DisasContext *ctx, arg_vr *a, MemOp mop) ++{ ++ return gvec_dup_vl(ctx, a, 16, mop); ++} ++ ++static bool gvec_dupx(DisasContext *ctx, arg_vr *a, MemOp mop) ++{ ++ return gvec_dup_vl(ctx, a, 32, mop); ++} ++ ++TRANS(vreplgr2vr_b, LSX, gvec_dup, MO_8) ++TRANS(vreplgr2vr_h, LSX, gvec_dup, MO_16) ++TRANS(vreplgr2vr_w, LSX, gvec_dup, MO_32) ++TRANS(vreplgr2vr_d, LSX, gvec_dup, MO_64) ++TRANS(xvreplgr2vr_b, LASX, gvec_dupx, MO_8) ++TRANS(xvreplgr2vr_h, LASX, gvec_dupx, MO_16) ++TRANS(xvreplgr2vr_w, LASX, gvec_dupx, MO_32) ++TRANS(xvreplgr2vr_d, LASX, gvec_dupx, MO_64) ++ ++static bool trans_vreplvei_b(DisasContext *ctx, arg_vv_i *a) ++{ ++ if (!avail_LSX(ctx)) { ++ return false; ++ } ++ ++ if (!check_vec(ctx, 16)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_dup_mem(MO_8,vec_full_offset(a->vd), ++ offsetof(CPULoongArchState, ++ fpr[a->vj].vreg.B((a->imm))), ++ 16, ctx->vl/8); ++ return true; ++} ++ ++static bool trans_vreplvei_h(DisasContext *ctx, arg_vv_i *a) ++{ ++ if (!avail_LSX(ctx)) { ++ return false; ++ } ++ ++ if (!check_vec(ctx, 16)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_dup_mem(MO_16, vec_full_offset(a->vd), ++ offsetof(CPULoongArchState, ++ fpr[a->vj].vreg.H((a->imm))), ++ 16, ctx->vl/8); ++ return true; ++} ++static bool trans_vreplvei_w(DisasContext *ctx, arg_vv_i *a) ++{ ++ if (!avail_LSX(ctx)) { ++ return false; ++ } ++ ++ if (!check_vec(ctx, 16)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_dup_mem(MO_32, vec_full_offset(a->vd), ++ offsetof(CPULoongArchState, ++ fpr[a->vj].vreg.W((a->imm))), ++ 16, ctx->vl/8); ++ return true; ++} ++static bool trans_vreplvei_d(DisasContext *ctx, arg_vv_i *a) ++{ ++ if (!avail_LSX(ctx)) { ++ return false; ++ } ++ ++ if (!check_vec(ctx, 16)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_dup_mem(MO_64, vec_full_offset(a->vd), ++ offsetof(CPULoongArchState, ++ fpr[a->vj].vreg.D((a->imm))), ++ 16, ctx->vl/8); ++ return true; ++} ++ ++static bool gen_vreplve_vl(DisasContext *ctx, arg_vvr *a, ++ uint32_t oprsz, int vece, int bit, ++ void (*func)(TCGv_i64, TCGv_ptr, tcg_target_long)) ++{ ++ int i; ++ TCGv_i64 t0 = tcg_temp_new_i64(); ++ TCGv_ptr t1 = tcg_temp_new_ptr(); ++ TCGv_i64 t2 = tcg_temp_new_i64(); ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ tcg_gen_andi_i64(t0, gpr_src(ctx, a->rk, EXT_NONE), (LSX_LEN / bit) - 1); ++ tcg_gen_shli_i64(t0, t0, vece); ++ if (HOST_BIG_ENDIAN) { ++ tcg_gen_xori_i64(t0, t0, vece << ((LSX_LEN / bit) - 1)); ++ } ++ ++ tcg_gen_trunc_i64_ptr(t1, t0); ++ tcg_gen_add_ptr(t1, t1, tcg_env); ++ ++ for (i = 0; i < oprsz; i += 16) { ++ func(t2, t1, vec_full_offset(a->vj) + i); ++ tcg_gen_gvec_dup_i64(vece, vec_full_offset(a->vd) + i, 16, 16, t2); ++ } ++ ++ return true; ++} ++ ++static bool gen_vreplve(DisasContext *ctx, arg_vvr *a, int vece, int bit, ++ void (*func)(TCGv_i64, TCGv_ptr, tcg_target_long)) ++{ ++ return gen_vreplve_vl(ctx, a, 16, vece, bit, func); ++} ++ ++static bool gen_xvreplve(DisasContext *ctx, arg_vvr *a, int vece, int bit, ++ void (*func)(TCGv_i64, TCGv_ptr, tcg_target_long)) ++{ ++ return gen_vreplve_vl(ctx, a, 32, vece, bit, func); ++} ++ ++TRANS(vreplve_b, LSX, gen_vreplve, MO_8, 8, tcg_gen_ld8u_i64) ++TRANS(vreplve_h, LSX, gen_vreplve, MO_16, 16, tcg_gen_ld16u_i64) ++TRANS(vreplve_w, LSX, gen_vreplve, MO_32, 32, tcg_gen_ld32u_i64) ++TRANS(vreplve_d, LSX, gen_vreplve, MO_64, 64, tcg_gen_ld_i64) ++TRANS(xvreplve_b, LASX, gen_xvreplve, MO_8, 8, tcg_gen_ld8u_i64) ++TRANS(xvreplve_h, LASX, gen_xvreplve, MO_16, 16, tcg_gen_ld16u_i64) ++TRANS(xvreplve_w, LASX, gen_xvreplve, MO_32, 32, tcg_gen_ld32u_i64) ++TRANS(xvreplve_d, LASX, gen_xvreplve, MO_64, 64, tcg_gen_ld_i64) ++ ++static bool gen_xvrepl128(DisasContext *ctx, arg_vv_i *a, MemOp mop) ++{ ++ int i; ++ ++ if (!check_vec(ctx, 32)) { ++ return true; ++ } ++ ++ for (i = 0; i < 32; i += 16) { ++ tcg_gen_gvec_dup_mem(mop, vec_full_offset(a->vd) + i, ++ vec_reg_offset(a->vj, a->imm, mop) + i, 16, 16); ++ ++ } ++ return true; ++} ++ ++TRANS(xvrepl128vei_b, LASX, gen_xvrepl128, MO_8) ++TRANS(xvrepl128vei_h, LASX, gen_xvrepl128, MO_16) ++TRANS(xvrepl128vei_w, LASX, gen_xvrepl128, MO_32) ++TRANS(xvrepl128vei_d, LASX, gen_xvrepl128, MO_64) ++ ++static bool gen_xvreplve0(DisasContext *ctx, arg_vv *a, MemOp mop) ++{ ++ if (!check_vec(ctx, 32)) { ++ return true; ++ } ++ ++ tcg_gen_gvec_dup_mem(mop, vec_full_offset(a->vd), ++ vec_full_offset(a->vj), 32, 32); ++ return true; ++} ++ ++TRANS(xvreplve0_b, LASX, gen_xvreplve0, MO_8) ++TRANS(xvreplve0_h, LASX, gen_xvreplve0, MO_16) ++TRANS(xvreplve0_w, LASX, gen_xvreplve0, MO_32) ++TRANS(xvreplve0_d, LASX, gen_xvreplve0, MO_64) ++TRANS(xvreplve0_q, LASX, gen_xvreplve0, MO_128) ++ ++TRANS(xvinsve0_w, LASX, gen_xx_i, gen_helper_xvinsve0_w) ++TRANS(xvinsve0_d, LASX, gen_xx_i, gen_helper_xvinsve0_d) ++ ++TRANS(xvpickve_w, LASX, gen_xx_i, gen_helper_xvpickve_w) ++TRANS(xvpickve_d, LASX, gen_xx_i, gen_helper_xvpickve_d) ++ ++static bool do_vbsll_v(DisasContext *ctx, arg_vv_i *a, uint32_t oprsz) ++{ ++ int i, ofs; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ TCGv desthigh = tcg_temp_new_i64(); ++ TCGv destlow = tcg_temp_new_i64(); ++ TCGv high = tcg_temp_new_i64(); ++ TCGv low = tcg_temp_new_i64(); ++ ++ get_vreg64(low, a->vj, 2 * i); ++ ++ ofs = ((a->imm) & 0xf) * 8; ++ if (ofs < 64) { ++ get_vreg64(high, a->vj, 2 * i + 1); ++ tcg_gen_extract2_i64(desthigh, low, high, 64 - ofs); ++ tcg_gen_shli_i64(destlow, low, ofs); ++ } else { ++ tcg_gen_shli_i64(desthigh, low, ofs - 64); ++ destlow = tcg_constant_i64(0); ++ } ++ set_vreg64(desthigh, a->vd, 2 * i + 1); ++ set_vreg64(destlow, a->vd, 2 * i); ++ } ++ ++ return true; ++} ++ ++static bool do_vbsrl_v(DisasContext *ctx, arg_vv_i *a, uint32_t oprsz) ++{ ++ int i, ofs; ++ ++ if (!check_vec(ctx, 32)) { ++ return true; ++ } ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ TCGv desthigh = tcg_temp_new_i64(); ++ TCGv destlow = tcg_temp_new_i64(); ++ TCGv high = tcg_temp_new_i64(); ++ TCGv low = tcg_temp_new_i64(); ++ get_vreg64(high, a->vj, 2 * i + 1); ++ ++ ofs = ((a->imm) & 0xf) * 8; ++ if (ofs < 64) { ++ get_vreg64(low, a->vj, 2 * i); ++ tcg_gen_extract2_i64(destlow, low, high, ofs); ++ tcg_gen_shri_i64(desthigh, high, ofs); ++ } else { ++ tcg_gen_shri_i64(destlow, high, ofs - 64); ++ desthigh = tcg_constant_i64(0); ++ } ++ set_vreg64(desthigh, a->vd, 2 * i + 1); ++ set_vreg64(destlow, a->vd, 2 * i); ++ } ++ ++ return true; ++} ++ ++TRANS(vbsll_v, LSX, do_vbsll_v, 16) ++TRANS(vbsrl_v, LSX, do_vbsrl_v, 16) ++TRANS(xvbsll_v, LASX, do_vbsll_v, 32) ++TRANS(xvbsrl_v, LASX, do_vbsrl_v, 32) ++ ++TRANS(vpackev_b, LSX, gen_vvv, gen_helper_vpackev_b) ++TRANS(vpackev_h, LSX, gen_vvv, gen_helper_vpackev_h) ++TRANS(vpackev_w, LSX, gen_vvv, gen_helper_vpackev_w) ++TRANS(vpackev_d, LSX, gen_vvv, gen_helper_vpackev_d) ++TRANS(vpackod_b, LSX, gen_vvv, gen_helper_vpackod_b) ++TRANS(vpackod_h, LSX, gen_vvv, gen_helper_vpackod_h) ++TRANS(vpackod_w, LSX, gen_vvv, gen_helper_vpackod_w) ++TRANS(vpackod_d, LSX, gen_vvv, gen_helper_vpackod_d) ++TRANS(xvpackev_b, LASX, gen_xxx, gen_helper_vpackev_b) ++TRANS(xvpackev_h, LASX, gen_xxx, gen_helper_vpackev_h) ++TRANS(xvpackev_w, LASX, gen_xxx, gen_helper_vpackev_w) ++TRANS(xvpackev_d, LASX, gen_xxx, gen_helper_vpackev_d) ++TRANS(xvpackod_b, LASX, gen_xxx, gen_helper_vpackod_b) ++TRANS(xvpackod_h, LASX, gen_xxx, gen_helper_vpackod_h) ++TRANS(xvpackod_w, LASX, gen_xxx, gen_helper_vpackod_w) ++TRANS(xvpackod_d, LASX, gen_xxx, gen_helper_vpackod_d) ++ ++TRANS(vpickev_b, LSX, gen_vvv, gen_helper_vpickev_b) ++TRANS(vpickev_h, LSX, gen_vvv, gen_helper_vpickev_h) ++TRANS(vpickev_w, LSX, gen_vvv, gen_helper_vpickev_w) ++TRANS(vpickev_d, LSX, gen_vvv, gen_helper_vpickev_d) ++TRANS(vpickod_b, LSX, gen_vvv, gen_helper_vpickod_b) ++TRANS(vpickod_h, LSX, gen_vvv, gen_helper_vpickod_h) ++TRANS(vpickod_w, LSX, gen_vvv, gen_helper_vpickod_w) ++TRANS(vpickod_d, LSX, gen_vvv, gen_helper_vpickod_d) ++TRANS(xvpickev_b, LASX, gen_xxx, gen_helper_vpickev_b) ++TRANS(xvpickev_h, LASX, gen_xxx, gen_helper_vpickev_h) ++TRANS(xvpickev_w, LASX, gen_xxx, gen_helper_vpickev_w) ++TRANS(xvpickev_d, LASX, gen_xxx, gen_helper_vpickev_d) ++TRANS(xvpickod_b, LASX, gen_xxx, gen_helper_vpickod_b) ++TRANS(xvpickod_h, LASX, gen_xxx, gen_helper_vpickod_h) ++TRANS(xvpickod_w, LASX, gen_xxx, gen_helper_vpickod_w) ++TRANS(xvpickod_d, LASX, gen_xxx, gen_helper_vpickod_d) ++ ++TRANS(vilvl_b, LSX, gen_vvv, gen_helper_vilvl_b) ++TRANS(vilvl_h, LSX, gen_vvv, gen_helper_vilvl_h) ++TRANS(vilvl_w, LSX, gen_vvv, gen_helper_vilvl_w) ++TRANS(vilvl_d, LSX, gen_vvv, gen_helper_vilvl_d) ++TRANS(vilvh_b, LSX, gen_vvv, gen_helper_vilvh_b) ++TRANS(vilvh_h, LSX, gen_vvv, gen_helper_vilvh_h) ++TRANS(vilvh_w, LSX, gen_vvv, gen_helper_vilvh_w) ++TRANS(vilvh_d, LSX, gen_vvv, gen_helper_vilvh_d) ++TRANS(xvilvl_b, LASX, gen_xxx, gen_helper_vilvl_b) ++TRANS(xvilvl_h, LASX, gen_xxx, gen_helper_vilvl_h) ++TRANS(xvilvl_w, LASX, gen_xxx, gen_helper_vilvl_w) ++TRANS(xvilvl_d, LASX, gen_xxx, gen_helper_vilvl_d) ++TRANS(xvilvh_b, LASX, gen_xxx, gen_helper_vilvh_b) ++TRANS(xvilvh_h, LASX, gen_xxx, gen_helper_vilvh_h) ++TRANS(xvilvh_w, LASX, gen_xxx, gen_helper_vilvh_w) ++TRANS(xvilvh_d, LASX, gen_xxx, gen_helper_vilvh_d) ++ ++TRANS(vshuf_b, LSX, gen_vvvv, gen_helper_vshuf_b) ++TRANS(vshuf_h, LSX, gen_vvv, gen_helper_vshuf_h) ++TRANS(vshuf_w, LSX, gen_vvv, gen_helper_vshuf_w) ++TRANS(vshuf_d, LSX, gen_vvv, gen_helper_vshuf_d) ++TRANS(xvshuf_b, LASX, gen_xxxx, gen_helper_vshuf_b) ++TRANS(xvshuf_h, LASX, gen_xxx, gen_helper_vshuf_h) ++TRANS(xvshuf_w, LASX, gen_xxx, gen_helper_vshuf_w) ++TRANS(xvshuf_d, LASX, gen_xxx, gen_helper_vshuf_d) ++TRANS(vshuf4i_b, LSX, gen_vv_i, gen_helper_vshuf4i_b) ++TRANS(vshuf4i_h, LSX, gen_vv_i, gen_helper_vshuf4i_h) ++TRANS(vshuf4i_w, LSX, gen_vv_i, gen_helper_vshuf4i_w) ++TRANS(vshuf4i_d, LSX, gen_vv_i, gen_helper_vshuf4i_d) ++TRANS(xvshuf4i_b, LASX, gen_xx_i, gen_helper_vshuf4i_b) ++TRANS(xvshuf4i_h, LASX, gen_xx_i, gen_helper_vshuf4i_h) ++TRANS(xvshuf4i_w, LASX, gen_xx_i, gen_helper_vshuf4i_w) ++TRANS(xvshuf4i_d, LASX, gen_xx_i, gen_helper_vshuf4i_d) ++ ++TRANS(xvperm_w, LASX, gen_xxx, gen_helper_vperm_w) ++TRANS(vpermi_w, LSX, gen_vv_i, gen_helper_vpermi_w) ++TRANS(xvpermi_w, LASX, gen_xx_i, gen_helper_vpermi_w) ++TRANS(xvpermi_d, LASX, gen_xx_i, gen_helper_vpermi_d) ++TRANS(xvpermi_q, LASX, gen_xx_i, gen_helper_vpermi_q) ++ ++TRANS(vextrins_b, LSX, gen_vv_i, gen_helper_vextrins_b) ++TRANS(vextrins_h, LSX, gen_vv_i, gen_helper_vextrins_h) ++TRANS(vextrins_w, LSX, gen_vv_i, gen_helper_vextrins_w) ++TRANS(vextrins_d, LSX, gen_vv_i, gen_helper_vextrins_d) ++TRANS(xvextrins_b, LASX, gen_xx_i, gen_helper_vextrins_b) ++TRANS(xvextrins_h, LASX, gen_xx_i, gen_helper_vextrins_h) ++TRANS(xvextrins_w, LASX, gen_xx_i, gen_helper_vextrins_w) ++TRANS(xvextrins_d, LASX, gen_xx_i, gen_helper_vextrins_d) ++ ++static bool trans_vld(DisasContext *ctx, arg_vr_i *a) ++{ ++ TCGv addr; ++ TCGv_i64 rl, rh; ++ TCGv_i128 val; ++ ++ if (!avail_LSX(ctx)) { ++ return false; ++ } ++ ++ if (!check_vec(ctx, 16)) { ++ return true; ++ } ++ ++ addr = gpr_src(ctx, a->rj, EXT_NONE); ++ val = tcg_temp_new_i128(); ++ rl = tcg_temp_new_i64(); ++ rh = tcg_temp_new_i64(); ++ ++ addr = make_address_i(ctx, addr, a->imm); ++ ++ tcg_gen_qemu_ld_i128(val, addr, ctx->mem_idx, MO_128 | MO_TE); ++ tcg_gen_extr_i128_i64(rl, rh, val); ++ set_vreg64(rh, a->vd, 1); ++ set_vreg64(rl, a->vd, 0); ++ ++ return true; ++} ++ ++static bool trans_vst(DisasContext *ctx, arg_vr_i *a) ++{ ++ TCGv addr; ++ TCGv_i128 val; ++ TCGv_i64 ah, al; ++ ++ if (!avail_LSX(ctx)) { ++ return false; ++ } ++ ++ if (!check_vec(ctx, 16)) { ++ return true; ++ } ++ ++ addr = gpr_src(ctx, a->rj, EXT_NONE); ++ val = tcg_temp_new_i128(); ++ ah = tcg_temp_new_i64(); ++ al = tcg_temp_new_i64(); ++ ++ addr = make_address_i(ctx, addr, a->imm); ++ ++ get_vreg64(ah, a->vd, 1); ++ get_vreg64(al, a->vd, 0); ++ tcg_gen_concat_i64_i128(val, al, ah); ++ tcg_gen_qemu_st_i128(val, addr, ctx->mem_idx, MO_128 | MO_TE); ++ ++ return true; ++} ++ ++static bool trans_vldx(DisasContext *ctx, arg_vrr *a) ++{ ++ TCGv addr, src1, src2; ++ TCGv_i64 rl, rh; ++ TCGv_i128 val; ++ ++ if (!avail_LSX(ctx)) { ++ return false; ++ } ++ ++ if (!check_vec(ctx, 16)) { ++ return true; ++ } ++ ++ src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ val = tcg_temp_new_i128(); ++ rl = tcg_temp_new_i64(); ++ rh = tcg_temp_new_i64(); ++ ++ addr = make_address_x(ctx, src1, src2); ++ tcg_gen_qemu_ld_i128(val, addr, ctx->mem_idx, MO_128 | MO_TE); ++ tcg_gen_extr_i128_i64(rl, rh, val); ++ set_vreg64(rh, a->vd, 1); ++ set_vreg64(rl, a->vd, 0); ++ ++ return true; ++} ++ ++static bool trans_vstx(DisasContext *ctx, arg_vrr *a) ++{ ++ TCGv addr, src1, src2; ++ TCGv_i64 ah, al; ++ TCGv_i128 val; ++ ++ if (!avail_LSX(ctx)) { ++ return false; ++ } ++ ++ if (!check_vec(ctx, 16)) { ++ return true; ++ } ++ ++ src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ val = tcg_temp_new_i128(); ++ ah = tcg_temp_new_i64(); ++ al = tcg_temp_new_i64(); ++ ++ addr = make_address_x(ctx, src1, src2); ++ get_vreg64(ah, a->vd, 1); ++ get_vreg64(al, a->vd, 0); ++ tcg_gen_concat_i64_i128(val, al, ah); ++ tcg_gen_qemu_st_i128(val, addr, ctx->mem_idx, MO_128 | MO_TE); ++ ++ return true; ++} ++ ++static bool do_vldrepl_vl(DisasContext *ctx, arg_vr_i *a, ++ uint32_t oprsz, MemOp mop) ++{ ++ TCGv addr; ++ TCGv_i64 val; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ addr = gpr_src(ctx, a->rj, EXT_NONE); ++ val = tcg_temp_new_i64(); ++ ++ addr = make_address_i(ctx, addr, a->imm); ++ ++ tcg_gen_qemu_ld_i64(val, addr, ctx->mem_idx, mop); ++ tcg_gen_gvec_dup_i64(mop, vec_full_offset(a->vd), oprsz, ctx->vl / 8, val); ++ ++ return true; ++} ++ ++static bool do_vldrepl(DisasContext *ctx, arg_vr_i *a, MemOp mop) ++{ ++ return do_vldrepl_vl(ctx, a, 16, mop); ++} ++ ++static bool do_xvldrepl(DisasContext *ctx, arg_vr_i *a, MemOp mop) ++{ ++ return do_vldrepl_vl(ctx, a, 32, mop); ++} ++ ++TRANS(vldrepl_b, LSX, do_vldrepl, MO_8) ++TRANS(vldrepl_h, LSX, do_vldrepl, MO_16) ++TRANS(vldrepl_w, LSX, do_vldrepl, MO_32) ++TRANS(vldrepl_d, LSX, do_vldrepl, MO_64) ++TRANS(xvldrepl_b, LASX, do_xvldrepl, MO_8) ++TRANS(xvldrepl_h, LASX, do_xvldrepl, MO_16) ++TRANS(xvldrepl_w, LASX, do_xvldrepl, MO_32) ++TRANS(xvldrepl_d, LASX, do_xvldrepl, MO_64) ++ ++static bool do_vstelm_vl(DisasContext *ctx, ++ arg_vr_ii *a, uint32_t oprsz, MemOp mop) ++{ ++ TCGv addr; ++ TCGv_i64 val; ++ ++ if (!check_vec(ctx, oprsz)) { ++ return true; ++ } ++ ++ addr = gpr_src(ctx, a->rj, EXT_NONE); ++ val = tcg_temp_new_i64(); ++ ++ addr = make_address_i(ctx, addr, a->imm); ++ tcg_gen_ld_i64(val, tcg_env, vec_reg_offset(a->vd, a->imm2, mop)); ++ tcg_gen_qemu_st_i64(val, addr, ctx->mem_idx, mop); ++ return true; ++} ++ ++static bool do_vstelm(DisasContext *ctx, arg_vr_ii *a, MemOp mop) ++{ ++ return do_vstelm_vl(ctx, a, 16, mop); ++} ++ ++static bool do_xvstelm(DisasContext *ctx, arg_vr_ii *a, MemOp mop) ++{ ++ return do_vstelm_vl(ctx, a, 32, mop); ++} ++ ++TRANS(vstelm_b, LSX, do_vstelm, MO_8) ++TRANS(vstelm_h, LSX, do_vstelm, MO_16) ++TRANS(vstelm_w, LSX, do_vstelm, MO_32) ++TRANS(vstelm_d, LSX, do_vstelm, MO_64) ++TRANS(xvstelm_b, LASX, do_xvstelm, MO_8) ++TRANS(xvstelm_h, LASX, do_xvstelm, MO_16) ++TRANS(xvstelm_w, LASX, do_xvstelm, MO_32) ++TRANS(xvstelm_d, LASX, do_xvstelm, MO_64) ++ ++static bool gen_lasx_memory(DisasContext *ctx, arg_vr_i *a, ++ void (*func)(DisasContext *, int, TCGv)) ++{ ++ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv temp = NULL; ++ ++ if (!check_vec(ctx, 32)) { ++ return true; ++ } ++ ++ if (a->imm) { ++ temp = tcg_temp_new(); ++ tcg_gen_addi_tl(temp, addr, a->imm); ++ addr = temp; ++ } ++ ++ func(ctx, a->vd, addr); ++ return true; ++} ++ ++static void gen_xvld(DisasContext *ctx, int vreg, TCGv addr) ++{ ++ int i; ++ TCGv temp = tcg_temp_new(); ++ TCGv dest = tcg_temp_new(); ++ ++ tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUQ); ++ set_vreg64(dest, vreg, 0); ++ ++ for (i = 1; i < 4; i++) { ++ tcg_gen_addi_tl(temp, addr, 8 * i); ++ tcg_gen_qemu_ld_i64(dest, temp, ctx->mem_idx, MO_TEUQ); ++ set_vreg64(dest, vreg, i); ++ } ++} ++ ++static void gen_xvst(DisasContext * ctx, int vreg, TCGv addr) ++{ ++ int i; ++ TCGv temp = tcg_temp_new(); ++ TCGv dest = tcg_temp_new(); ++ ++ get_vreg64(dest, vreg, 0); ++ tcg_gen_qemu_st_i64(dest, addr, ctx->mem_idx, MO_TEUQ); ++ ++ for (i = 1; i < 4; i++) { ++ tcg_gen_addi_tl(temp, addr, 8 * i); ++ get_vreg64(dest, vreg, i); ++ tcg_gen_qemu_st_i64(dest, temp, ctx->mem_idx, MO_TEUQ); ++ } ++} ++ ++TRANS(xvld, LASX, gen_lasx_memory, gen_xvld) ++TRANS(xvst, LASX, gen_lasx_memory, gen_xvst) ++ ++static bool gen_lasx_memoryx(DisasContext *ctx, arg_vrr *a, ++ void (*func)(DisasContext*, int, TCGv)) ++{ ++ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); ++ TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); ++ TCGv addr = tcg_temp_new(); ++ ++ if (!check_vec(ctx, 32)) { ++ return true; ++ } ++ ++ tcg_gen_add_tl(addr, src1, src2); ++ func(ctx, a->vd, addr); ++ ++ return true; ++} ++ ++TRANS(xvldx, LASX, gen_lasx_memoryx, gen_xvld) ++TRANS(xvstx, LASX, gen_lasx_memoryx, gen_xvst) +diff --git a/target/loongarch/tcg/iocsr_helper.c b/target/loongarch/tcg/iocsr_helper.c +new file mode 100644 +index 0000000..6cd01d5 +--- /dev/null ++++ b/target/loongarch/tcg/iocsr_helper.c +@@ -0,0 +1,68 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ * ++ * Helpers for IOCSR reads/writes ++ */ ++ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "qemu/host-utils.h" ++#include "exec/helper-proto.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++ ++#define GET_MEMTXATTRS(cas) \ ++ ((MemTxAttrs){.requester_id = env_cpu(cas)->cpu_index}) ++ ++uint64_t helper_iocsrrd_b(CPULoongArchState *env, target_ulong r_addr) ++{ ++ return address_space_ldub(&env->address_space_iocsr, r_addr, ++ GET_MEMTXATTRS(env), NULL); ++} ++ ++uint64_t helper_iocsrrd_h(CPULoongArchState *env, target_ulong r_addr) ++{ ++ return address_space_lduw(&env->address_space_iocsr, r_addr, ++ GET_MEMTXATTRS(env), NULL); ++} ++ ++uint64_t helper_iocsrrd_w(CPULoongArchState *env, target_ulong r_addr) ++{ ++ return address_space_ldl(&env->address_space_iocsr, r_addr, ++ GET_MEMTXATTRS(env), NULL); ++} ++ ++uint64_t helper_iocsrrd_d(CPULoongArchState *env, target_ulong r_addr) ++{ ++ return address_space_ldq(&env->address_space_iocsr, r_addr, ++ GET_MEMTXATTRS(env), NULL); ++} ++ ++void helper_iocsrwr_b(CPULoongArchState *env, target_ulong w_addr, ++ target_ulong val) ++{ ++ address_space_stb(&env->address_space_iocsr, w_addr, ++ val, GET_MEMTXATTRS(env), NULL); ++} ++ ++void helper_iocsrwr_h(CPULoongArchState *env, target_ulong w_addr, ++ target_ulong val) ++{ ++ address_space_stw(&env->address_space_iocsr, w_addr, ++ val, GET_MEMTXATTRS(env), NULL); ++} ++ ++void helper_iocsrwr_w(CPULoongArchState *env, target_ulong w_addr, ++ target_ulong val) ++{ ++ address_space_stl(&env->address_space_iocsr, w_addr, ++ val, GET_MEMTXATTRS(env), NULL); ++} ++ ++void helper_iocsrwr_d(CPULoongArchState *env, target_ulong w_addr, ++ target_ulong val) ++{ ++ address_space_stq(&env->address_space_iocsr, w_addr, ++ val, GET_MEMTXATTRS(env), NULL); ++} +diff --git a/target/loongarch/tcg/meson.build b/target/loongarch/tcg/meson.build +new file mode 100644 +index 0000000..1a3cd58 +--- /dev/null ++++ b/target/loongarch/tcg/meson.build +@@ -0,0 +1,19 @@ ++if 'CONFIG_TCG' not in config_all ++ subdir_done() ++endif ++ ++loongarch_ss.add([zlib, gen]) ++ ++loongarch_ss.add(files( ++ 'fpu_helper.c', ++ 'op_helper.c', ++ 'translate.c', ++ 'vec_helper.c', ++)) ++ ++loongarch_system_ss.add(files( ++ 'constant_timer.c', ++ 'csr_helper.c', ++ 'iocsr_helper.c', ++ 'tlb_helper.c', ++)) +diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c +new file mode 100644 +index 0000000..fe79c62 +--- /dev/null ++++ b/target/loongarch/tcg/op_helper.c +@@ -0,0 +1,140 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch emulation helpers for QEMU. ++ * ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/log.h" ++#include "cpu.h" ++#include "qemu/host-utils.h" ++#include "exec/helper-proto.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++#include "internals.h" ++#include "qemu/crc32c.h" ++#include ++#include "cpu-csr.h" ++ ++/* Exceptions helpers */ ++void helper_raise_exception(CPULoongArchState *env, uint32_t exception) ++{ ++ do_raise_exception(env, exception, GETPC()); ++} ++ ++target_ulong helper_bitrev_w(target_ulong rj) ++{ ++ return (int32_t)revbit32(rj); ++} ++ ++target_ulong helper_bitrev_d(target_ulong rj) ++{ ++ return revbit64(rj); ++} ++ ++target_ulong helper_bitswap(target_ulong v) ++{ ++ v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | ++ ((v & (target_ulong)0x5555555555555555ULL) << 1); ++ v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | ++ ((v & (target_ulong)0x3333333333333333ULL) << 2); ++ v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | ++ ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); ++ return v; ++} ++ ++/* loongarch assert op */ ++void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) ++{ ++ if (rj > rk) { ++ env->CSR_BADV = rj; ++ do_raise_exception(env, EXCCODE_BCE, GETPC()); ++ } ++} ++ ++void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) ++{ ++ if (rj <= rk) { ++ env->CSR_BADV = rj; ++ do_raise_exception(env, EXCCODE_BCE, GETPC()); ++ } ++} ++ ++target_ulong helper_crc32(target_ulong val, target_ulong m, uint64_t sz) ++{ ++ uint8_t buf[8]; ++ target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); ++ ++ m &= mask; ++ stq_le_p(buf, m); ++ return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); ++} ++ ++target_ulong helper_crc32c(target_ulong val, target_ulong m, uint64_t sz) ++{ ++ uint8_t buf[8]; ++ target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); ++ m &= mask; ++ stq_le_p(buf, m); ++ return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff); ++} ++ ++target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj) ++{ ++ return rj >= ARRAY_SIZE(env->cpucfg) ? 0 : env->cpucfg[rj]; ++} ++ ++uint64_t helper_rdtime_d(CPULoongArchState *env) ++{ ++#ifdef CONFIG_USER_ONLY ++ return cpu_get_host_ticks(); ++#else ++ uint64_t plv; ++ LoongArchCPU *cpu = env_archcpu(env); ++ ++ plv = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV); ++ if (extract64(env->CSR_MISC, R_CSR_MISC_DRDTL_SHIFT + plv, 1)) { ++ do_raise_exception(env, EXCCODE_IPE, GETPC()); ++ } ++ ++ return cpu_loongarch_get_constant_timer_counter(cpu); ++#endif ++} ++ ++#ifndef CONFIG_USER_ONLY ++void helper_ertn(CPULoongArchState *env) ++{ ++ uint64_t csr_pplv, csr_pie; ++ if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { ++ csr_pplv = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV); ++ csr_pie = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE); ++ ++ env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); ++ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 0); ++ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 1); ++ set_pc(env, env->CSR_TLBRERA); ++ qemu_log_mask(CPU_LOG_INT, "%s: TLBRERA " TARGET_FMT_lx "\n", ++ __func__, env->CSR_TLBRERA); ++ } else { ++ csr_pplv = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PPLV); ++ csr_pie = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PIE); ++ ++ set_pc(env, env->CSR_ERA); ++ qemu_log_mask(CPU_LOG_INT, "%s: ERA " TARGET_FMT_lx "\n", ++ __func__, env->CSR_ERA); ++ } ++ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, csr_pplv); ++ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, csr_pie); ++ ++ env->lladdr = 1; ++} ++ ++void helper_idle(CPULoongArchState *env) ++{ ++ CPUState *cs = env_cpu(env); ++ ++ cs->halted = 1; ++ do_raise_exception(env, EXCP_HLT, 0); ++} ++#endif +diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c +new file mode 100644 +index 0000000..449043c +--- /dev/null ++++ b/target/loongarch/tcg/tlb_helper.c +@@ -0,0 +1,803 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * QEMU LoongArch TLB helpers ++ * ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/guest-random.h" ++ ++#include "cpu.h" ++#include "internals.h" ++#include "exec/helper-proto.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++#include "exec/log.h" ++#include "cpu-csr.h" ++ ++enum { ++ TLBRET_MATCH = 0, ++ TLBRET_BADADDR = 1, ++ TLBRET_NOMATCH = 2, ++ TLBRET_INVALID = 3, ++ TLBRET_DIRTY = 4, ++ TLBRET_RI = 5, ++ TLBRET_XI = 6, ++ TLBRET_PE = 7, ++}; ++ ++static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, ++ int *prot, target_ulong address, ++ int access_type, int index, int mmu_idx) ++{ ++ LoongArchTLB *tlb = &env->tlb[index]; ++ uint64_t plv = mmu_idx; ++ uint64_t tlb_entry, tlb_ppn; ++ uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv; ++ ++ if (index >= LOONGARCH_STLB) { ++ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); ++ } else { ++ tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); ++ } ++ n = (address >> tlb_ps) & 0x1;/* Odd or even */ ++ ++ tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0; ++ tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V); ++ tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D); ++ tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV); ++ if (is_la64(env)) { ++ tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN); ++ tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY_64, NX); ++ tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY_64, NR); ++ tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY_64, RPLV); ++ } else { ++ tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_32, PPN); ++ tlb_nx = 0; ++ tlb_nr = 0; ++ tlb_rplv = 0; ++ } ++ ++ /* Remove sw bit between bit12 -- bit PS*/ ++ tlb_ppn = tlb_ppn & ~(((0x1UL << (tlb_ps - 12)) -1)); ++ ++ /* Check access rights */ ++ if (!tlb_v) { ++ return TLBRET_INVALID; ++ } ++ ++ if (access_type == MMU_INST_FETCH && tlb_nx) { ++ return TLBRET_XI; ++ } ++ ++ if (access_type == MMU_DATA_LOAD && tlb_nr) { ++ return TLBRET_RI; ++ } ++ ++ if (((tlb_rplv == 0) && (plv > tlb_plv)) || ++ ((tlb_rplv == 1) && (plv != tlb_plv))) { ++ return TLBRET_PE; ++ } ++ ++ if ((access_type == MMU_DATA_STORE) && !tlb_d) { ++ return TLBRET_DIRTY; ++ } ++ ++ *physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) | ++ (address & MAKE_64BIT_MASK(0, tlb_ps)); ++ *prot = PAGE_READ; ++ if (tlb_d) { ++ *prot |= PAGE_WRITE; ++ } ++ if (!tlb_nx) { ++ *prot |= PAGE_EXEC; ++ } ++ return TLBRET_MATCH; ++} ++ ++/* ++ * One tlb entry holds an adjacent odd/even pair, the vpn is the ++ * content of the virtual page number divided by 2. So the ++ * compare vpn is bit[47:15] for 16KiB page. while the vppn ++ * field in tlb entry contains bit[47:13], so need adjust. ++ * virt_vpn = vaddr[47:13] ++ */ ++static bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, ++ int *index) ++{ ++ LoongArchTLB *tlb; ++ uint16_t csr_asid, tlb_asid, stlb_idx; ++ uint8_t tlb_e, tlb_ps, tlb_g, stlb_ps; ++ int i, compare_shift; ++ uint64_t vpn, tlb_vppn; ++ ++ csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); ++ stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); ++ vpn = (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1); ++ stlb_idx = vpn & 0xff; /* VA[25:15] <==> TLBIDX.index for 16KiB Page */ ++ compare_shift = stlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; ++ ++ /* Search STLB */ ++ for (i = 0; i < 8; ++i) { ++ tlb = &env->tlb[i * 256 + stlb_idx]; ++ tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); ++ if (tlb_e) { ++ tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); ++ tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); ++ tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); ++ ++ if ((tlb_g == 1 || tlb_asid == csr_asid) && ++ (vpn == (tlb_vppn >> compare_shift))) { ++ *index = i * 256 + stlb_idx; ++ return true; ++ } ++ } ++ } ++ ++ /* Search MTLB */ ++ for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; ++i) { ++ tlb = &env->tlb[i]; ++ tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); ++ if (tlb_e) { ++ tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); ++ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); ++ tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); ++ tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); ++ compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; ++ vpn = (vaddr & TARGET_VIRT_MASK) >> (tlb_ps + 1); ++ if ((tlb_g == 1 || tlb_asid == csr_asid) && ++ (vpn == (tlb_vppn >> compare_shift))) { ++ *index = i; ++ return true; ++ } ++ } ++ } ++ return false; ++} ++ ++static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, ++ int *prot, target_ulong address, ++ MMUAccessType access_type, int mmu_idx) ++{ ++ int index, match; ++ ++ match = loongarch_tlb_search(env, address, &index); ++ if (match) { ++ return loongarch_map_tlb_entry(env, physical, prot, ++ address, access_type, index, mmu_idx); ++ } ++ ++ return TLBRET_NOMATCH; ++} ++ ++static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va, ++ target_ulong dmw) ++{ ++ if (is_la64(env)) { ++ return va & TARGET_VIRT_MASK; ++ } else { ++ uint32_t pseg = FIELD_EX32(dmw, CSR_DMW_32, PSEG); ++ return (va & MAKE_64BIT_MASK(0, R_CSR_DMW_32_VSEG_SHIFT)) | \ ++ (pseg << R_CSR_DMW_32_VSEG_SHIFT); ++ } ++} ++ ++static int get_physical_address(CPULoongArchState *env, hwaddr *physical, ++ int *prot, target_ulong address, ++ MMUAccessType access_type, int mmu_idx) ++{ ++ int user_mode = mmu_idx == MMU_IDX_USER; ++ int kernel_mode = mmu_idx == MMU_IDX_KERNEL; ++ uint32_t plv, base_c, base_v; ++ int64_t addr_high; ++ uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA); ++ uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG); ++ ++ /* Check PG and DA */ ++ if (da & !pg) { ++ *physical = address & TARGET_PHYS_MASK; ++ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ return TLBRET_MATCH; ++ } ++ ++ plv = kernel_mode | (user_mode << R_CSR_DMW_PLV3_SHIFT); ++ if (is_la64(env)) { ++ base_v = address >> R_CSR_DMW_64_VSEG_SHIFT; ++ } else { ++ base_v = address >> R_CSR_DMW_32_VSEG_SHIFT; ++ } ++ /* Check direct map window */ ++ for (int i = 0; i < 4; i++) { ++ if (is_la64(env)) { ++ base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW_64, VSEG); ++ } else { ++ base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW_32, VSEG); ++ } ++ if ((plv & env->CSR_DMW[i]) && (base_c == base_v)) { ++ *physical = dmw_va2pa(env, address, env->CSR_DMW[i]); ++ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ return TLBRET_MATCH; ++ } ++ } ++ ++ /* Check valid extension */ ++ addr_high = sextract64(address, TARGET_VIRT_ADDR_SPACE_BITS, 16); ++ if (!(addr_high == 0 || addr_high == -1)) { ++ return TLBRET_BADADDR; ++ } ++ ++ /* Mapped address */ ++ return loongarch_map_address(env, physical, prot, address, ++ access_type, mmu_idx); ++} ++ ++hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(cs); ++ CPULoongArchState *env = &cpu->env; ++ hwaddr phys_addr; ++ int prot; ++ ++ if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD, ++ cpu_mmu_index(env, false)) != 0) { ++ return -1; ++ } ++ return phys_addr; ++} ++ ++static void raise_mmu_exception(CPULoongArchState *env, target_ulong address, ++ MMUAccessType access_type, int tlb_error) ++{ ++ CPUState *cs = env_cpu(env); ++ ++ switch (tlb_error) { ++ default: ++ case TLBRET_BADADDR: ++ cs->exception_index = access_type == MMU_INST_FETCH ++ ? EXCCODE_ADEF : EXCCODE_ADEM; ++ break; ++ case TLBRET_NOMATCH: ++ /* No TLB match for a mapped address */ ++ if (access_type == MMU_DATA_LOAD) { ++ cs->exception_index = EXCCODE_PIL; ++ } else if (access_type == MMU_DATA_STORE) { ++ cs->exception_index = EXCCODE_PIS; ++ } else if (access_type == MMU_INST_FETCH) { ++ cs->exception_index = EXCCODE_PIF; ++ } ++ env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 1); ++ break; ++ case TLBRET_INVALID: ++ /* TLB match with no valid bit */ ++ if (access_type == MMU_DATA_LOAD) { ++ cs->exception_index = EXCCODE_PIL; ++ } else if (access_type == MMU_DATA_STORE) { ++ cs->exception_index = EXCCODE_PIS; ++ } else if (access_type == MMU_INST_FETCH) { ++ cs->exception_index = EXCCODE_PIF; ++ } ++ break; ++ case TLBRET_DIRTY: ++ /* TLB match but 'D' bit is cleared */ ++ cs->exception_index = EXCCODE_PME; ++ break; ++ case TLBRET_XI: ++ /* Execute-Inhibit Exception */ ++ cs->exception_index = EXCCODE_PNX; ++ break; ++ case TLBRET_RI: ++ /* Read-Inhibit Exception */ ++ cs->exception_index = EXCCODE_PNR; ++ break; ++ case TLBRET_PE: ++ /* Privileged Exception */ ++ cs->exception_index = EXCCODE_PPI; ++ break; ++ } ++ ++ if (tlb_error == TLBRET_NOMATCH) { ++ env->CSR_TLBRBADV = address; ++ if (is_la64(env)) { ++ env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI_64, ++ VPPN, extract64(address, 13, 35)); ++ } else { ++ env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI_32, ++ VPPN, extract64(address, 13, 19)); ++ } ++ } else { ++ if (!FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) { ++ env->CSR_BADV = address; ++ } ++ env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1); ++ } ++} ++ ++static void invalidate_tlb_entry(CPULoongArchState *env, int index) ++{ ++ target_ulong addr, mask, pagesize; ++ uint8_t tlb_ps; ++ LoongArchTLB *tlb = &env->tlb[index]; ++ ++ int mmu_idx = cpu_mmu_index(env, false); ++ uint8_t tlb_v0 = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, V); ++ uint8_t tlb_v1 = FIELD_EX64(tlb->tlb_entry1, TLBENTRY, V); ++ uint64_t tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); ++ ++ if (index >= LOONGARCH_STLB) { ++ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); ++ } else { ++ tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); ++ } ++ pagesize = MAKE_64BIT_MASK(tlb_ps, 1); ++ mask = MAKE_64BIT_MASK(0, tlb_ps + 1); ++ ++ if (tlb_v0) { ++ addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & ~mask; /* even */ ++ tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize, ++ mmu_idx, TARGET_LONG_BITS); ++ } ++ ++ if (tlb_v1) { ++ addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & pagesize; /* odd */ ++ tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize, ++ mmu_idx, TARGET_LONG_BITS); ++ } ++} ++ ++static void invalidate_tlb(CPULoongArchState *env, int index) ++{ ++ LoongArchTLB *tlb; ++ uint16_t csr_asid, tlb_asid, tlb_g; ++ ++ csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); ++ tlb = &env->tlb[index]; ++ tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); ++ tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); ++ if (tlb_g == 0 && tlb_asid != csr_asid) { ++ return; ++ } ++ invalidate_tlb_entry(env, index); ++} ++ ++static void fill_tlb_entry(CPULoongArchState *env, int index) ++{ ++ LoongArchTLB *tlb = &env->tlb[index]; ++ uint64_t lo0, lo1, csr_vppn; ++ uint16_t csr_asid; ++ uint8_t csr_ps; ++ ++ if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { ++ csr_ps = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS); ++ if (is_la64(env)) { ++ csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI_64, VPPN); ++ } else { ++ csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI_32, VPPN); ++ } ++ lo0 = env->CSR_TLBRELO0; ++ lo1 = env->CSR_TLBRELO1; ++ } else { ++ csr_ps = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS); ++ if (is_la64(env)) { ++ csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI_64, VPPN); ++ } else { ++ csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI_32, VPPN); ++ } ++ lo0 = env->CSR_TLBELO0; ++ lo1 = env->CSR_TLBELO1; ++ } ++ ++ if (csr_ps == 0) { ++ qemu_log_mask(CPU_LOG_MMU, "page size is 0\n"); ++ } ++ ++ /* Only MTLB has the ps fields */ ++ if (index >= LOONGARCH_STLB) { ++ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, PS, csr_ps); ++ } ++ ++ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, VPPN, csr_vppn); ++ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 1); ++ csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); ++ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, ASID, csr_asid); ++ ++ tlb->tlb_entry0 = lo0; ++ tlb->tlb_entry1 = lo1; ++} ++ ++/* Return an random value between low and high */ ++static uint32_t get_random_tlb(uint32_t low, uint32_t high) ++{ ++ uint32_t val; ++ ++ qemu_guest_getrandom_nofail(&val, sizeof(val)); ++ return val % (high - low + 1) + low; ++} ++ ++void helper_tlbsrch(CPULoongArchState *env) ++{ ++ int index, match; ++ ++ if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { ++ match = loongarch_tlb_search(env, env->CSR_TLBREHI, &index); ++ } else { ++ match = loongarch_tlb_search(env, env->CSR_TLBEHI, &index); ++ } ++ ++ if (match) { ++ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX, index); ++ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0); ++ return; ++ } ++ ++ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1); ++} ++ ++void helper_tlbrd(CPULoongArchState *env) ++{ ++ LoongArchTLB *tlb; ++ int index; ++ uint8_t tlb_ps, tlb_e; ++ ++ index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); ++ tlb = &env->tlb[index]; ++ ++ if (index >= LOONGARCH_STLB) { ++ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); ++ } else { ++ tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); ++ } ++ tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); ++ ++ if (!tlb_e) { ++ /* Invalid TLB entry */ ++ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1); ++ env->CSR_ASID = FIELD_DP64(env->CSR_ASID, CSR_ASID, ASID, 0); ++ env->CSR_TLBEHI = 0; ++ env->CSR_TLBELO0 = 0; ++ env->CSR_TLBELO1 = 0; ++ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, PS, 0); ++ } else { ++ /* Valid TLB entry */ ++ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0); ++ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, ++ PS, (tlb_ps & 0x3f)); ++ env->CSR_TLBEHI = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN) << ++ R_TLB_MISC_VPPN_SHIFT; ++ env->CSR_TLBELO0 = tlb->tlb_entry0; ++ env->CSR_TLBELO1 = tlb->tlb_entry1; ++ } ++} ++ ++void helper_tlbwr(CPULoongArchState *env) ++{ ++ int index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); ++ ++ invalidate_tlb(env, index); ++ ++ if (FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, NE)) { ++ env->tlb[index].tlb_misc = FIELD_DP64(env->tlb[index].tlb_misc, ++ TLB_MISC, E, 0); ++ return; ++ } ++ ++ fill_tlb_entry(env, index); ++} ++ ++void helper_tlbfill(CPULoongArchState *env) ++{ ++ uint64_t address, entryhi; ++ int index, set, stlb_idx; ++ uint16_t pagesize, stlb_ps; ++ ++ if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { ++ entryhi = env->CSR_TLBREHI; ++ pagesize = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS); ++ } else { ++ entryhi = env->CSR_TLBEHI; ++ pagesize = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS); ++ } ++ ++ stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); ++ ++ if (pagesize == stlb_ps) { ++ /* Only write into STLB bits [47:13] */ ++ address = entryhi & ~MAKE_64BIT_MASK(0, R_CSR_TLBEHI_64_VPPN_SHIFT); ++ ++ /* Choose one set ramdomly */ ++ set = get_random_tlb(0, 7); ++ ++ /* Index in one set */ ++ stlb_idx = (address >> (stlb_ps + 1)) & 0xff; /* [0,255] */ ++ ++ index = set * 256 + stlb_idx; ++ } else { ++ /* Only write into MTLB */ ++ index = get_random_tlb(LOONGARCH_STLB, LOONGARCH_TLB_MAX - 1); ++ } ++ ++ invalidate_tlb(env, index); ++ fill_tlb_entry(env, index); ++} ++ ++void helper_tlbclr(CPULoongArchState *env) ++{ ++ LoongArchTLB *tlb; ++ int i, index; ++ uint16_t csr_asid, tlb_asid, tlb_g; ++ ++ csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); ++ index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); ++ ++ if (index < LOONGARCH_STLB) { ++ /* STLB. One line per operation */ ++ for (i = 0; i < 8; i++) { ++ tlb = &env->tlb[i * 256 + (index % 256)]; ++ tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); ++ tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); ++ if (!tlb_g && tlb_asid == csr_asid) { ++ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); ++ } ++ } ++ } else if (index < LOONGARCH_TLB_MAX) { ++ /* All MTLB entries */ ++ for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { ++ tlb = &env->tlb[i]; ++ tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); ++ tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); ++ if (!tlb_g && tlb_asid == csr_asid) { ++ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); ++ } ++ } ++ } ++ ++ tlb_flush(env_cpu(env)); ++} ++ ++void helper_tlbflush(CPULoongArchState *env) ++{ ++ int i, index; ++ ++ index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); ++ ++ if (index < LOONGARCH_STLB) { ++ /* STLB. One line per operation */ ++ for (i = 0; i < 8; i++) { ++ int s_idx = i * 256 + (index % 256); ++ env->tlb[s_idx].tlb_misc = FIELD_DP64(env->tlb[s_idx].tlb_misc, ++ TLB_MISC, E, 0); ++ } ++ } else if (index < LOONGARCH_TLB_MAX) { ++ /* All MTLB entries */ ++ for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { ++ env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc, ++ TLB_MISC, E, 0); ++ } ++ } ++ ++ tlb_flush(env_cpu(env)); ++} ++ ++void helper_invtlb_all(CPULoongArchState *env) ++{ ++ for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { ++ env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc, ++ TLB_MISC, E, 0); ++ } ++ tlb_flush(env_cpu(env)); ++} ++ ++void helper_invtlb_all_g(CPULoongArchState *env, uint32_t g) ++{ ++ for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { ++ LoongArchTLB *tlb = &env->tlb[i]; ++ uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); ++ ++ if (tlb_g == g) { ++ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); ++ } ++ } ++ tlb_flush(env_cpu(env)); ++} ++ ++void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info) ++{ ++ uint16_t asid = info & R_CSR_ASID_ASID_MASK; ++ ++ for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { ++ LoongArchTLB *tlb = &env->tlb[i]; ++ uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); ++ uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); ++ ++ if (!tlb_g && (tlb_asid == asid)) { ++ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); ++ } ++ } ++ tlb_flush(env_cpu(env)); ++} ++ ++void helper_invtlb_page_asid(CPULoongArchState *env, target_ulong info, ++ target_ulong addr) ++{ ++ uint16_t asid = info & 0x3ff; ++ ++ for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { ++ LoongArchTLB *tlb = &env->tlb[i]; ++ uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); ++ uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); ++ uint64_t vpn, tlb_vppn; ++ uint8_t tlb_ps, compare_shift; ++ ++ if (i >= LOONGARCH_STLB) { ++ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); ++ } else { ++ tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); ++ } ++ tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); ++ vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1); ++ compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; ++ ++ if (!tlb_g && (tlb_asid == asid) && ++ (vpn == (tlb_vppn >> compare_shift))) { ++ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); ++ } ++ } ++ tlb_flush(env_cpu(env)); ++} ++ ++void helper_invtlb_page_asid_or_g(CPULoongArchState *env, ++ target_ulong info, target_ulong addr) ++{ ++ uint16_t asid = info & 0x3ff; ++ ++ for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { ++ LoongArchTLB *tlb = &env->tlb[i]; ++ uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); ++ uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); ++ uint64_t vpn, tlb_vppn; ++ uint8_t tlb_ps, compare_shift; ++ ++ if (i >= LOONGARCH_STLB) { ++ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); ++ } else { ++ tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); ++ } ++ tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); ++ vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1); ++ compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; ++ ++ if ((tlb_g || (tlb_asid == asid)) && ++ (vpn == (tlb_vppn >> compare_shift))) { ++ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); ++ } ++ } ++ tlb_flush(env_cpu(env)); ++} ++ ++bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ++ MMUAccessType access_type, int mmu_idx, ++ bool probe, uintptr_t retaddr) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(cs); ++ CPULoongArchState *env = &cpu->env; ++ hwaddr physical; ++ int prot; ++ int ret; ++ ++ /* Data access */ ++ ret = get_physical_address(env, &physical, &prot, address, ++ access_type, mmu_idx); ++ ++ if (ret == TLBRET_MATCH) { ++ tlb_set_page(cs, address & TARGET_PAGE_MASK, ++ physical & TARGET_PAGE_MASK, prot, ++ mmu_idx, TARGET_PAGE_SIZE); ++ qemu_log_mask(CPU_LOG_MMU, ++ "%s address=%" VADDR_PRIx " physical " HWADDR_FMT_plx ++ " prot %d\n", __func__, address, physical, prot); ++ return true; ++ } else { ++ qemu_log_mask(CPU_LOG_MMU, ++ "%s address=%" VADDR_PRIx " ret %d\n", __func__, address, ++ ret); ++ } ++ if (probe) { ++ return false; ++ } ++ raise_mmu_exception(env, address, access_type, ret); ++ cpu_loop_exit_restore(cs, retaddr); ++} ++ ++target_ulong helper_lddir(CPULoongArchState *env, target_ulong base, ++ target_ulong level, uint32_t mem_idx) ++{ ++ CPUState *cs = env_cpu(env); ++ target_ulong badvaddr, index, phys, ret; ++ int shift; ++ uint64_t dir_base, dir_width; ++ bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1; ++ ++ badvaddr = env->CSR_TLBRBADV; ++ base = base & TARGET_PHYS_MASK; ++ ++ /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */ ++ shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); ++ shift = (shift + 1) * 3; ++ ++ if (huge) { ++ return base; ++ } ++ switch (level) { ++ case 1: ++ dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE); ++ dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH); ++ break; ++ case 2: ++ dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE); ++ dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH); ++ break; ++ case 3: ++ dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE); ++ dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH); ++ break; ++ case 4: ++ dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE); ++ dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH); ++ break; ++ default: ++ do_raise_exception(env, EXCCODE_INE, GETPC()); ++ return 0; ++ } ++ index = (badvaddr >> dir_base) & ((1 << dir_width) - 1); ++ phys = base | index << shift; ++ ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; ++ return ret; ++} ++ ++void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd, ++ uint32_t mem_idx) ++{ ++ CPUState *cs = env_cpu(env); ++ target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv; ++ int shift; ++ bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1; ++ uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); ++ uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH); ++ ++ base = base & TARGET_PHYS_MASK; ++ ++ if (huge) { ++ /* Huge Page. base is paddr */ ++ tmp0 = base ^ (1 << LOONGARCH_PAGE_HUGE_SHIFT); ++ /* Move Global bit */ ++ tmp0 = ((tmp0 & (1 << LOONGARCH_HGLOBAL_SHIFT)) >> ++ LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT | ++ (tmp0 & (~(1 << LOONGARCH_HGLOBAL_SHIFT))); ++ ps = ptbase + ptwidth - 1; ++ if (odd) { ++ tmp0 += MAKE_64BIT_MASK(ps, 1); ++ } ++ } else { ++ /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */ ++ shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); ++ shift = (shift + 1) * 3; ++ badv = env->CSR_TLBRBADV; ++ ++ ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1); ++ ptindex = ptindex & ~0x1; /* clear bit 0 */ ++ ptoffset0 = ptindex << shift; ++ ptoffset1 = (ptindex + 1) << shift; ++ ++ phys = base | (odd ? ptoffset1 : ptoffset0); ++ tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; ++ ps = ptbase; ++ } ++ ++ if (odd) { ++ env->CSR_TLBRELO1 = tmp0; ++ } else { ++ env->CSR_TLBRELO0 = tmp0; ++ } ++ env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, PS, ps); ++} +diff --git a/target/loongarch/tcg/translate.c b/target/loongarch/tcg/translate.c +new file mode 100644 +index 0000000..21f4db6 +--- /dev/null ++++ b/target/loongarch/tcg/translate.c +@@ -0,0 +1,370 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch emulation for QEMU - main translation routines. ++ * ++ * Copyright (c) 2021 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "tcg/tcg-op.h" ++#include "tcg/tcg-op-gvec.h" ++#include "exec/translation-block.h" ++#include "exec/translator.h" ++#include "exec/helper-proto.h" ++#include "exec/helper-gen.h" ++#include "exec/log.h" ++#include "qemu/qemu-print.h" ++#include "fpu/softfloat.h" ++#include "translate.h" ++#include "internals.h" ++#include "vec.h" ++ ++/* Global register indices */ ++TCGv cpu_gpr[32], cpu_pc; ++static TCGv cpu_lladdr, cpu_llval; ++ ++#define HELPER_H "helper.h" ++#include "exec/helper-info.c.inc" ++#undef HELPER_H ++ ++#define DISAS_STOP DISAS_TARGET_0 ++#define DISAS_EXIT DISAS_TARGET_1 ++#define DISAS_EXIT_UPDATE DISAS_TARGET_2 ++ ++static inline int vec_full_offset(int regno) ++{ ++ return offsetof(CPULoongArchState, fpr[regno]); ++} ++ ++static inline int vec_reg_offset(int regno, int index, MemOp mop) ++{ ++ const uint8_t size = 1 << mop; ++ int offs = index * size; ++ ++ if (HOST_BIG_ENDIAN && size < 8 ) { ++ offs ^= (8 - size); ++ } ++ ++ return offs + vec_full_offset(regno); ++} ++ ++static inline void get_vreg64(TCGv_i64 dest, int regno, int index) ++{ ++ tcg_gen_ld_i64(dest, tcg_env, ++ offsetof(CPULoongArchState, fpr[regno].vreg.D(index))); ++} ++ ++static inline void set_vreg64(TCGv_i64 src, int regno, int index) ++{ ++ tcg_gen_st_i64(src, tcg_env, ++ offsetof(CPULoongArchState, fpr[regno].vreg.D(index))); ++} ++ ++static inline int plus_1(DisasContext *ctx, int x) ++{ ++ return x + 1; ++} ++ ++static inline int shl_1(DisasContext *ctx, int x) ++{ ++ return x << 1; ++} ++ ++static inline int shl_2(DisasContext *ctx, int x) ++{ ++ return x << 2; ++} ++ ++static inline int shl_3(DisasContext *ctx, int x) ++{ ++ return x << 3; ++} ++ ++/* ++ * LoongArch the upper 32 bits are undefined ("can be any value"). ++ * QEMU chooses to nanbox, because it is most likely to show guest bugs early. ++ */ ++static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in) ++{ ++ tcg_gen_ori_i64(out, in, MAKE_64BIT_MASK(32, 32)); ++} ++ ++void generate_exception(DisasContext *ctx, int excp) ++{ ++ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); ++ gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp)); ++ ctx->base.is_jmp = DISAS_NORETURN; ++} ++ ++static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) ++{ ++ if (ctx->va32) { ++ dest = (uint32_t) dest; ++ } ++ ++ if (translator_use_goto_tb(&ctx->base, dest)) { ++ tcg_gen_goto_tb(n); ++ tcg_gen_movi_tl(cpu_pc, dest); ++ tcg_gen_exit_tb(ctx->base.tb, n); ++ } else { ++ tcg_gen_movi_tl(cpu_pc, dest); ++ tcg_gen_lookup_and_goto_ptr(); ++ } ++} ++ ++static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, ++ CPUState *cs) ++{ ++ int64_t bound; ++ CPULoongArchState *env = cpu_env(cs); ++ DisasContext *ctx = container_of(dcbase, DisasContext, base); ++ ++ ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; ++ ctx->plv = ctx->base.tb->flags & HW_FLAGS_PLV_MASK; ++ if (ctx->base.tb->flags & HW_FLAGS_CRMD_PG) { ++ ctx->mem_idx = ctx->plv; ++ } else { ++ ctx->mem_idx = MMU_IDX_DA; ++ } ++ ++ /* Bound the number of insns to execute to those left on the page. */ ++ bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; ++ ctx->base.max_insns = MIN(ctx->base.max_insns, bound); ++ ++ if (FIELD_EX64(env->cpucfg[2], CPUCFG2, LSX)) { ++ ctx->vl = LSX_LEN; ++ } ++ ++ if (FIELD_EX64(env->cpucfg[2], CPUCFG2, LASX)) { ++ ctx->vl = LASX_LEN; ++ } ++ ++ ctx->la64 = is_la64(env); ++ ctx->va32 = (ctx->base.tb->flags & HW_FLAGS_VA32) != 0; ++ ++ ctx->zero = tcg_constant_tl(0); ++ ++ ctx->cpucfg1 = env->cpucfg[1]; ++ ctx->cpucfg2 = env->cpucfg[2]; ++} ++ ++static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) ++{ ++} ++ ++static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) ++{ ++ DisasContext *ctx = container_of(dcbase, DisasContext, base); ++ ++ tcg_gen_insn_start(ctx->base.pc_next); ++} ++ ++/* ++ * Wrappers for getting reg values. ++ * ++ * The $zero register does not have cpu_gpr[0] allocated -- we supply the ++ * constant zero as a source, and an uninitialized sink as destination. ++ * ++ * Further, we may provide an extension for word operations. ++ */ ++static TCGv gpr_src(DisasContext *ctx, int reg_num, DisasExtend src_ext) ++{ ++ TCGv t; ++ ++ if (reg_num == 0) { ++ return ctx->zero; ++ } ++ ++ switch (src_ext) { ++ case EXT_NONE: ++ return cpu_gpr[reg_num]; ++ case EXT_SIGN: ++ t = tcg_temp_new(); ++ tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]); ++ return t; ++ case EXT_ZERO: ++ t = tcg_temp_new(); ++ tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]); ++ return t; ++ } ++ g_assert_not_reached(); ++} ++ ++static TCGv gpr_dst(DisasContext *ctx, int reg_num, DisasExtend dst_ext) ++{ ++ if (reg_num == 0 || dst_ext) { ++ return tcg_temp_new(); ++ } ++ return cpu_gpr[reg_num]; ++} ++ ++static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) ++{ ++ if (reg_num != 0) { ++ switch (dst_ext) { ++ case EXT_NONE: ++ tcg_gen_mov_tl(cpu_gpr[reg_num], t); ++ break; ++ case EXT_SIGN: ++ tcg_gen_ext32s_tl(cpu_gpr[reg_num], t); ++ break; ++ case EXT_ZERO: ++ tcg_gen_ext32u_tl(cpu_gpr[reg_num], t); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ } ++} ++ ++static TCGv get_fpr(DisasContext *ctx, int reg_num) ++{ ++ TCGv t = tcg_temp_new(); ++ tcg_gen_ld_i64(t, tcg_env, ++ offsetof(CPULoongArchState, fpr[reg_num].vreg.D(0))); ++ return t; ++} ++ ++static void set_fpr(int reg_num, TCGv val) ++{ ++ tcg_gen_st_i64(val, tcg_env, ++ offsetof(CPULoongArchState, fpr[reg_num].vreg.D(0))); ++} ++ ++static TCGv make_address_x(DisasContext *ctx, TCGv base, TCGv addend) ++{ ++ TCGv temp = NULL; ++ ++ if (addend || ctx->va32) { ++ temp = tcg_temp_new(); ++ } ++ if (addend) { ++ tcg_gen_add_tl(temp, base, addend); ++ base = temp; ++ } ++ if (ctx->va32) { ++ tcg_gen_ext32u_tl(temp, base); ++ base = temp; ++ } ++ return base; ++} ++ ++static TCGv make_address_i(DisasContext *ctx, TCGv base, target_long ofs) ++{ ++ TCGv addend = ofs ? tcg_constant_tl(ofs) : NULL; ++ return make_address_x(ctx, base, addend); ++} ++ ++static uint64_t make_address_pc(DisasContext *ctx, uint64_t addr) ++{ ++ if (ctx->va32) { ++ addr = (int32_t)addr; ++ } ++ return addr; ++} ++ ++#include "decode-insns.c.inc" ++#include "insn_trans/trans_arith.c.inc" ++#include "insn_trans/trans_shift.c.inc" ++#include "insn_trans/trans_bit.c.inc" ++#include "insn_trans/trans_memory.c.inc" ++#include "insn_trans/trans_atomic.c.inc" ++#include "insn_trans/trans_extra.c.inc" ++#include "insn_trans/trans_farith.c.inc" ++#include "insn_trans/trans_fcmp.c.inc" ++#include "insn_trans/trans_fcnv.c.inc" ++#include "insn_trans/trans_fmov.c.inc" ++#include "insn_trans/trans_fmemory.c.inc" ++#include "insn_trans/trans_branch.c.inc" ++#include "insn_trans/trans_privileged.c.inc" ++#include "insn_trans/trans_vec.c.inc" ++ ++static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ DisasContext *ctx = container_of(dcbase, DisasContext, base); ++ ++ ctx->opcode = translator_ldl(env, &ctx->base, ctx->base.pc_next); ++ ++ if (!decode(ctx, ctx->opcode)) { ++ qemu_log_mask(LOG_UNIMP, "Error: unknown opcode. " ++ TARGET_FMT_lx ": 0x%x\n", ++ ctx->base.pc_next, ctx->opcode); ++ generate_exception(ctx, EXCCODE_INE); ++ } ++ ++ ctx->base.pc_next += 4; ++ ++ if (ctx->va32) { ++ ctx->base.pc_next = (uint32_t)ctx->base.pc_next; ++ } ++} ++ ++static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) ++{ ++ DisasContext *ctx = container_of(dcbase, DisasContext, base); ++ ++ switch (ctx->base.is_jmp) { ++ case DISAS_STOP: ++ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); ++ tcg_gen_lookup_and_goto_ptr(); ++ break; ++ case DISAS_TOO_MANY: ++ gen_goto_tb(ctx, 0, ctx->base.pc_next); ++ break; ++ case DISAS_NORETURN: ++ break; ++ case DISAS_EXIT_UPDATE: ++ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); ++ QEMU_FALLTHROUGH; ++ case DISAS_EXIT: ++ tcg_gen_exit_tb(NULL, 0); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void loongarch_tr_disas_log(const DisasContextBase *dcbase, ++ CPUState *cpu, FILE *logfile) ++{ ++ qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); ++ target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); ++} ++ ++static const TranslatorOps loongarch_tr_ops = { ++ .init_disas_context = loongarch_tr_init_disas_context, ++ .tb_start = loongarch_tr_tb_start, ++ .insn_start = loongarch_tr_insn_start, ++ .translate_insn = loongarch_tr_translate_insn, ++ .tb_stop = loongarch_tr_tb_stop, ++ .disas_log = loongarch_tr_disas_log, ++}; ++ ++void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, ++ target_ulong pc, void *host_pc) ++{ ++ DisasContext ctx; ++ ++ translator_loop(cs, tb, max_insns, pc, host_pc, ++ &loongarch_tr_ops, &ctx.base); ++} ++ ++void loongarch_translate_init(void) ++{ ++ int i; ++ ++ cpu_gpr[0] = NULL; ++ for (i = 1; i < 32; i++) { ++ cpu_gpr[i] = tcg_global_mem_new(tcg_env, ++ offsetof(CPULoongArchState, gpr[i]), ++ regnames[i]); ++ } ++ ++ cpu_pc = tcg_global_mem_new(tcg_env, offsetof(CPULoongArchState, pc), "pc"); ++ cpu_lladdr = tcg_global_mem_new(tcg_env, ++ offsetof(CPULoongArchState, lladdr), "lladdr"); ++ cpu_llval = tcg_global_mem_new(tcg_env, ++ offsetof(CPULoongArchState, llval), "llval"); ++} +diff --git a/target/loongarch/tcg/vec_helper.c b/target/loongarch/tcg/vec_helper.c +new file mode 100644 +index 0000000..3faf52c +--- /dev/null ++++ b/target/loongarch/tcg/vec_helper.c +@@ -0,0 +1,3494 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * QEMU LoongArch vector helper functions. ++ * ++ * Copyright (c) 2022-2023 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "exec/helper-proto.h" ++#include "fpu/softfloat.h" ++#include "internals.h" ++#include "tcg/tcg.h" ++#include "vec.h" ++#include "tcg/tcg-gvec-desc.h" ++ ++#define DO_ODD_EVEN(NAME, BIT, E1, E2, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ typedef __typeof(Vd->E1(0)) TD; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E1(i) = DO_OP((TD)Vj->E2(2 * i + 1), (TD)Vk->E2(2 * i)); \ ++ } \ ++} ++ ++DO_ODD_EVEN(vhaddw_h_b, 16, H, B, DO_ADD) ++DO_ODD_EVEN(vhaddw_w_h, 32, W, H, DO_ADD) ++DO_ODD_EVEN(vhaddw_d_w, 64, D, W, DO_ADD) ++ ++void HELPER(vhaddw_q_d)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16 ; i++) { ++ Vd->Q(i) = int128_add(int128_makes64(Vj->D(2 * i + 1)), ++ int128_makes64(Vk->D(2 * i))); ++ } ++} ++ ++DO_ODD_EVEN(vhsubw_h_b, 16, H, B, DO_SUB) ++DO_ODD_EVEN(vhsubw_w_h, 32, W, H, DO_SUB) ++DO_ODD_EVEN(vhsubw_d_w, 64, D, W, DO_SUB) ++ ++void HELPER(vhsubw_q_d)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_sub(int128_makes64(Vj->D(2 * i + 1)), ++ int128_makes64(Vk->D(2 * i))); ++ } ++} ++ ++DO_ODD_EVEN(vhaddw_hu_bu, 16, UH, UB, DO_ADD) ++DO_ODD_EVEN(vhaddw_wu_hu, 32, UW, UH, DO_ADD) ++DO_ODD_EVEN(vhaddw_du_wu, 64, UD, UW, DO_ADD) ++ ++void HELPER(vhaddw_qu_du)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i ++) { ++ Vd->Q(i) = int128_add(int128_make64(Vj->UD(2 * i + 1)), ++ int128_make64(Vk->UD(2 * i))); ++ } ++} ++ ++DO_ODD_EVEN(vhsubw_hu_bu, 16, UH, UB, DO_SUB) ++DO_ODD_EVEN(vhsubw_wu_hu, 32, UW, UH, DO_SUB) ++DO_ODD_EVEN(vhsubw_du_wu, 64, UD, UW, DO_SUB) ++ ++void HELPER(vhsubw_qu_du)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_sub(int128_make64(Vj->UD(2 * i + 1)), ++ int128_make64(Vk->UD(2 * i))); ++ } ++} ++ ++#define DO_EVEN(NAME, BIT, E1, E2, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ typedef __typeof(Vd->E1(0)) TD; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E1(i) = DO_OP((TD)Vj->E2(2 * i) ,(TD)Vk->E2(2 * i)); \ ++ } \ ++} ++ ++#define DO_ODD(NAME, BIT, E1, E2, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ typedef __typeof(Vd->E1(0)) TD; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E1(i) = DO_OP((TD)Vj->E2(2 * i + 1), (TD)Vk->E2(2 * i + 1)); \ ++ } \ ++} ++ ++void HELPER(vaddwev_q_d)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_add(int128_makes64(Vj->D(2 * i)), ++ int128_makes64(Vk->D(2 * i))); ++ } ++} ++ ++DO_EVEN(vaddwev_h_b, 16, H, B, DO_ADD) ++DO_EVEN(vaddwev_w_h, 32, W, H, DO_ADD) ++DO_EVEN(vaddwev_d_w, 64, D, W, DO_ADD) ++ ++void HELPER(vaddwod_q_d)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_add(int128_makes64(Vj->D(2 * i +1)), ++ int128_makes64(Vk->D(2 * i +1))); ++ } ++} ++ ++DO_ODD(vaddwod_h_b, 16, H, B, DO_ADD) ++DO_ODD(vaddwod_w_h, 32, W, H, DO_ADD) ++DO_ODD(vaddwod_d_w, 64, D, W, DO_ADD) ++ ++void HELPER(vsubwev_q_d)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_sub(int128_makes64(Vj->D(2 * i)), ++ int128_makes64(Vk->D(2 * i))); ++ } ++} ++ ++DO_EVEN(vsubwev_h_b, 16, H, B, DO_SUB) ++DO_EVEN(vsubwev_w_h, 32, W, H, DO_SUB) ++DO_EVEN(vsubwev_d_w, 64, D, W, DO_SUB) ++ ++void HELPER(vsubwod_q_d)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_sub(int128_makes64(Vj->D(2 * i + 1)), ++ int128_makes64(Vk->D(2 * i + 1))); ++ } ++} ++ ++DO_ODD(vsubwod_h_b, 16, H, B, DO_SUB) ++DO_ODD(vsubwod_w_h, 32, W, H, DO_SUB) ++DO_ODD(vsubwod_d_w, 64, D, W, DO_SUB) ++ ++void HELPER(vaddwev_q_du)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_add(int128_make64(Vj->UD(2 * i)), ++ int128_make64(Vk->UD(2 * i))); ++ } ++} ++ ++DO_EVEN(vaddwev_h_bu, 16, UH, UB, DO_ADD) ++DO_EVEN(vaddwev_w_hu, 32, UW, UH, DO_ADD) ++DO_EVEN(vaddwev_d_wu, 64, UD, UW, DO_ADD) ++ ++void HELPER(vaddwod_q_du)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_add(int128_make64(Vj->UD(2 * i + 1)), ++ int128_make64(Vk->UD(2 * i + 1))); ++ } ++} ++ ++DO_ODD(vaddwod_h_bu, 16, UH, UB, DO_ADD) ++DO_ODD(vaddwod_w_hu, 32, UW, UH, DO_ADD) ++DO_ODD(vaddwod_d_wu, 64, UD, UW, DO_ADD) ++ ++void HELPER(vsubwev_q_du)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_sub(int128_make64(Vj->UD(2 * i)), ++ int128_make64(Vk->UD(2 * i))); ++ } ++} ++ ++DO_EVEN(vsubwev_h_bu, 16, UH, UB, DO_SUB) ++DO_EVEN(vsubwev_w_hu, 32, UW, UH, DO_SUB) ++DO_EVEN(vsubwev_d_wu, 64, UD, UW, DO_SUB) ++ ++void HELPER(vsubwod_q_du)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_sub(int128_make64(Vj->UD(2 * i + 1)), ++ int128_make64(Vk->UD(2 * i + 1))); ++ } ++} ++ ++DO_ODD(vsubwod_h_bu, 16, UH, UB, DO_SUB) ++DO_ODD(vsubwod_w_hu, 32, UW, UH, DO_SUB) ++DO_ODD(vsubwod_d_wu, 64, UD, UW, DO_SUB) ++ ++#define DO_EVEN_U_S(NAME, BIT, ES1, EU1, ES2, EU2, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ typedef __typeof(Vd->ES1(0)) TDS; \ ++ typedef __typeof(Vd->EU1(0)) TDU; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->ES1(i) = DO_OP((TDU)Vj->EU2(2 * i) ,(TDS)Vk->ES2(2 * i)); \ ++ } \ ++} ++ ++#define DO_ODD_U_S(NAME, BIT, ES1, EU1, ES2, EU2, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ typedef __typeof(Vd->ES1(0)) TDS; \ ++ typedef __typeof(Vd->EU1(0)) TDU; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->ES1(i) = DO_OP((TDU)Vj->EU2(2 * i + 1), (TDS)Vk->ES2(2 * i + 1)); \ ++ } \ ++} ++ ++void HELPER(vaddwev_q_du_d)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_add(int128_make64(Vj->UD(2 * i)), ++ int128_makes64(Vk->D(2 * i))); ++ } ++} ++ ++DO_EVEN_U_S(vaddwev_h_bu_b, 16, H, UH, B, UB, DO_ADD) ++DO_EVEN_U_S(vaddwev_w_hu_h, 32, W, UW, H, UH, DO_ADD) ++DO_EVEN_U_S(vaddwev_d_wu_w, 64, D, UD, W, UW, DO_ADD) ++ ++void HELPER(vaddwod_q_du_d)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_add(int128_make64(Vj->UD(2 * i + 1)), ++ int128_makes64(Vk->D(2 * i + 1))); ++ } ++} ++ ++DO_ODD_U_S(vaddwod_h_bu_b, 16, H, UH, B, UB, DO_ADD) ++DO_ODD_U_S(vaddwod_w_hu_h, 32, W, UW, H, UH, DO_ADD) ++DO_ODD_U_S(vaddwod_d_wu_w, 64, D, UD, W, UW, DO_ADD) ++ ++#define DO_3OP(NAME, BIT, E, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = DO_OP(Vj->E(i), Vk->E(i)); \ ++ } \ ++} ++ ++DO_3OP(vavg_b, 8, B, DO_VAVG) ++DO_3OP(vavg_h, 16, H, DO_VAVG) ++DO_3OP(vavg_w, 32, W, DO_VAVG) ++DO_3OP(vavg_d, 64, D, DO_VAVG) ++DO_3OP(vavgr_b, 8, B, DO_VAVGR) ++DO_3OP(vavgr_h, 16, H, DO_VAVGR) ++DO_3OP(vavgr_w, 32, W, DO_VAVGR) ++DO_3OP(vavgr_d, 64, D, DO_VAVGR) ++DO_3OP(vavg_bu, 8, UB, DO_VAVG) ++DO_3OP(vavg_hu, 16, UH, DO_VAVG) ++DO_3OP(vavg_wu, 32, UW, DO_VAVG) ++DO_3OP(vavg_du, 64, UD, DO_VAVG) ++DO_3OP(vavgr_bu, 8, UB, DO_VAVGR) ++DO_3OP(vavgr_hu, 16, UH, DO_VAVGR) ++DO_3OP(vavgr_wu, 32, UW, DO_VAVGR) ++DO_3OP(vavgr_du, 64, UD, DO_VAVGR) ++ ++DO_3OP(vabsd_b, 8, B, DO_VABSD) ++DO_3OP(vabsd_h, 16, H, DO_VABSD) ++DO_3OP(vabsd_w, 32, W, DO_VABSD) ++DO_3OP(vabsd_d, 64, D, DO_VABSD) ++DO_3OP(vabsd_bu, 8, UB, DO_VABSD) ++DO_3OP(vabsd_hu, 16, UH, DO_VABSD) ++DO_3OP(vabsd_wu, 32, UW, DO_VABSD) ++DO_3OP(vabsd_du, 64, UD, DO_VABSD) ++ ++#define DO_VADDA(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = DO_VABS(Vj->E(i)) + DO_VABS(Vk->E(i)); \ ++ } \ ++} ++ ++DO_VADDA(vadda_b, 8, B) ++DO_VADDA(vadda_h, 16, H) ++DO_VADDA(vadda_w, 32, W) ++DO_VADDA(vadda_d, 64, D) ++ ++#define VMINMAXI(NAME, BIT, E, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ typedef __typeof(Vd->E(0)) TD; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = DO_OP(Vj->E(i), (TD)imm); \ ++ } \ ++} ++ ++VMINMAXI(vmini_b, 8, B, DO_MIN) ++VMINMAXI(vmini_h, 16, H, DO_MIN) ++VMINMAXI(vmini_w, 32, W, DO_MIN) ++VMINMAXI(vmini_d, 64, D, DO_MIN) ++VMINMAXI(vmaxi_b, 8, B, DO_MAX) ++VMINMAXI(vmaxi_h, 16, H, DO_MAX) ++VMINMAXI(vmaxi_w, 32, W, DO_MAX) ++VMINMAXI(vmaxi_d, 64, D, DO_MAX) ++VMINMAXI(vmini_bu, 8, UB, DO_MIN) ++VMINMAXI(vmini_hu, 16, UH, DO_MIN) ++VMINMAXI(vmini_wu, 32, UW, DO_MIN) ++VMINMAXI(vmini_du, 64, UD, DO_MIN) ++VMINMAXI(vmaxi_bu, 8, UB, DO_MAX) ++VMINMAXI(vmaxi_hu, 16, UH, DO_MAX) ++VMINMAXI(vmaxi_wu, 32, UW, DO_MAX) ++VMINMAXI(vmaxi_du, 64, UD, DO_MAX) ++ ++#define DO_VMUH(NAME, BIT, E1, E2, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ typedef __typeof(Vd->E1(0)) T; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E2(i) = ((T)Vj->E2(i)) * ((T)Vk->E2(i)) >> BIT; \ ++ } \ ++} ++ ++void HELPER(vmuh_d)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ uint64_t l, h; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 8; i++) { ++ muls64(&l, &h, Vj->D(i), Vk->D(i)); ++ Vd->D(i) = h; ++ } ++} ++ ++DO_VMUH(vmuh_b, 8, H, B, DO_MUH) ++DO_VMUH(vmuh_h, 16, W, H, DO_MUH) ++DO_VMUH(vmuh_w, 32, D, W, DO_MUH) ++ ++void HELPER(vmuh_du)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i; ++ uint64_t l, h; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 8; i++) { ++ mulu64(&l, &h, Vj->D(i), Vk->D(i)); ++ Vd->D(i) = h; ++ } ++} ++ ++DO_VMUH(vmuh_bu, 8, UH, UB, DO_MUH) ++DO_VMUH(vmuh_hu, 16, UW, UH, DO_MUH) ++DO_VMUH(vmuh_wu, 32, UD, UW, DO_MUH) ++ ++DO_EVEN(vmulwev_h_b, 16, H, B, DO_MUL) ++DO_EVEN(vmulwev_w_h, 32, W, H, DO_MUL) ++DO_EVEN(vmulwev_d_w, 64, D, W, DO_MUL) ++ ++DO_ODD(vmulwod_h_b, 16, H, B, DO_MUL) ++DO_ODD(vmulwod_w_h, 32, W, H, DO_MUL) ++DO_ODD(vmulwod_d_w, 64, D, W, DO_MUL) ++ ++DO_EVEN(vmulwev_h_bu, 16, UH, UB, DO_MUL) ++DO_EVEN(vmulwev_w_hu, 32, UW, UH, DO_MUL) ++DO_EVEN(vmulwev_d_wu, 64, UD, UW, DO_MUL) ++ ++DO_ODD(vmulwod_h_bu, 16, UH, UB, DO_MUL) ++DO_ODD(vmulwod_w_hu, 32, UW, UH, DO_MUL) ++DO_ODD(vmulwod_d_wu, 64, UD, UW, DO_MUL) ++ ++DO_EVEN_U_S(vmulwev_h_bu_b, 16, H, UH, B, UB, DO_MUL) ++DO_EVEN_U_S(vmulwev_w_hu_h, 32, W, UW, H, UH, DO_MUL) ++DO_EVEN_U_S(vmulwev_d_wu_w, 64, D, UD, W, UW, DO_MUL) ++ ++DO_ODD_U_S(vmulwod_h_bu_b, 16, H, UH, B, UB, DO_MUL) ++DO_ODD_U_S(vmulwod_w_hu_h, 32, W, UW, H, UH, DO_MUL) ++DO_ODD_U_S(vmulwod_d_wu_w, 64, D, UD, W, UW, DO_MUL) ++ ++#define VMADDSUB(NAME, BIT, E, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = DO_OP(Vd->E(i), Vj->E(i) ,Vk->E(i)); \ ++ } \ ++} ++ ++VMADDSUB(vmadd_b, 8, B, DO_MADD) ++VMADDSUB(vmadd_h, 16, H, DO_MADD) ++VMADDSUB(vmadd_w, 32, W, DO_MADD) ++VMADDSUB(vmadd_d, 64, D, DO_MADD) ++VMADDSUB(vmsub_b, 8, B, DO_MSUB) ++VMADDSUB(vmsub_h, 16, H, DO_MSUB) ++VMADDSUB(vmsub_w, 32, W, DO_MSUB) ++VMADDSUB(vmsub_d, 64, D, DO_MSUB) ++ ++#define VMADDWEV(NAME, BIT, E1, E2, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ typedef __typeof(Vd->E1(0)) TD; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E1(i) += DO_OP((TD)Vj->E2(2 * i), (TD)Vk->E2(2 * i)); \ ++ } \ ++} ++ ++VMADDWEV(vmaddwev_h_b, 16, H, B, DO_MUL) ++VMADDWEV(vmaddwev_w_h, 32, W, H, DO_MUL) ++VMADDWEV(vmaddwev_d_w, 64, D, W, DO_MUL) ++VMADDWEV(vmaddwev_h_bu, 16, UH, UB, DO_MUL) ++VMADDWEV(vmaddwev_w_hu, 32, UW, UH, DO_MUL) ++VMADDWEV(vmaddwev_d_wu, 64, UD, UW, DO_MUL) ++ ++#define VMADDWOD(NAME, BIT, E1, E2, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ typedef __typeof(Vd->E1(0)) TD; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E1(i) += DO_OP((TD)Vj->E2(2 * i + 1), \ ++ (TD)Vk->E2(2 * i + 1)); \ ++ } \ ++} ++ ++VMADDWOD(vmaddwod_h_b, 16, H, B, DO_MUL) ++VMADDWOD(vmaddwod_w_h, 32, W, H, DO_MUL) ++VMADDWOD(vmaddwod_d_w, 64, D, W, DO_MUL) ++VMADDWOD(vmaddwod_h_bu, 16, UH, UB, DO_MUL) ++VMADDWOD(vmaddwod_w_hu, 32, UW, UH, DO_MUL) ++VMADDWOD(vmaddwod_d_wu, 64, UD, UW, DO_MUL) ++ ++#define VMADDWEV_U_S(NAME, BIT, ES1, EU1, ES2, EU2, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ typedef __typeof(Vd->ES1(0)) TS1; \ ++ typedef __typeof(Vd->EU1(0)) TU1; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->ES1(i) += DO_OP((TU1)Vj->EU2(2 * i), \ ++ (TS1)Vk->ES2(2 * i)); \ ++ } \ ++} ++ ++VMADDWEV_U_S(vmaddwev_h_bu_b, 16, H, UH, B, UB, DO_MUL) ++VMADDWEV_U_S(vmaddwev_w_hu_h, 32, W, UW, H, UH, DO_MUL) ++VMADDWEV_U_S(vmaddwev_d_wu_w, 64, D, UD, W, UW, DO_MUL) ++ ++#define VMADDWOD_U_S(NAME, BIT, ES1, EU1, ES2, EU2, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ typedef __typeof(Vd->ES1(0)) TS1; \ ++ typedef __typeof(Vd->EU1(0)) TU1; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->ES1(i) += DO_OP((TU1)Vj->EU2(2 * i + 1), \ ++ (TS1)Vk->ES2(2 * i + 1)); \ ++ } \ ++} ++ ++VMADDWOD_U_S(vmaddwod_h_bu_b, 16, H, UH, B, UB, DO_MUL) ++VMADDWOD_U_S(vmaddwod_w_hu_h, 32, W, UW, H, UH, DO_MUL) ++VMADDWOD_U_S(vmaddwod_d_wu_w, 64, D, UD, W, UW, DO_MUL) ++ ++#define VDIV(NAME, BIT, E, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = DO_OP(Vj->E(i), Vk->E(i)); \ ++ } \ ++} ++ ++VDIV(vdiv_b, 8, B, DO_DIV) ++VDIV(vdiv_h, 16, H, DO_DIV) ++VDIV(vdiv_w, 32, W, DO_DIV) ++VDIV(vdiv_d, 64, D, DO_DIV) ++VDIV(vdiv_bu, 8, UB, DO_DIVU) ++VDIV(vdiv_hu, 16, UH, DO_DIVU) ++VDIV(vdiv_wu, 32, UW, DO_DIVU) ++VDIV(vdiv_du, 64, UD, DO_DIVU) ++VDIV(vmod_b, 8, B, DO_REM) ++VDIV(vmod_h, 16, H, DO_REM) ++VDIV(vmod_w, 32, W, DO_REM) ++VDIV(vmod_d, 64, D, DO_REM) ++VDIV(vmod_bu, 8, UB, DO_REMU) ++VDIV(vmod_hu, 16, UH, DO_REMU) ++VDIV(vmod_wu, 32, UW, DO_REMU) ++VDIV(vmod_du, 64, UD, DO_REMU) ++ ++#define VSAT_S(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t max, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ typedef __typeof(Vd->E(0)) TD; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = Vj->E(i) > (TD)max ? (TD)max : \ ++ Vj->E(i) < (TD)~max ? (TD)~max: Vj->E(i); \ ++ } \ ++} ++ ++VSAT_S(vsat_b, 8, B) ++VSAT_S(vsat_h, 16, H) ++VSAT_S(vsat_w, 32, W) ++VSAT_S(vsat_d, 64, D) ++ ++#define VSAT_U(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t max, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ typedef __typeof(Vd->E(0)) TD; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = Vj->E(i) > (TD)max ? (TD)max : Vj->E(i); \ ++ } \ ++} ++ ++VSAT_U(vsat_bu, 8, UB) ++VSAT_U(vsat_hu, 16, UH) ++VSAT_U(vsat_wu, 32, UW) ++VSAT_U(vsat_du, 64, UD) ++ ++#define VEXTH(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + i * ofs) = Vj->E2(j + ofs + ofs * 2 * i); \ ++ } \ ++ } \ ++} ++ ++void HELPER(vexth_q_d)(void *vd, void *vj, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_makes64(Vj->D(2 * i + 1)); ++ } ++} ++ ++void HELPER(vexth_qu_du)(void *vd, void *vj, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_make64(Vj->UD(2 * i + 1)); ++ } ++} ++ ++VEXTH(vexth_h_b, 16, H, B) ++VEXTH(vexth_w_h, 32, W, H) ++VEXTH(vexth_d_w, 64, D, W) ++VEXTH(vexth_hu_bu, 16, UH, UB) ++VEXTH(vexth_wu_hu, 32, UW, UH) ++VEXTH(vexth_du_wu, 64, UD, UW) ++ ++#define VEXT2XV(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ temp.E1(i) = Vj->E2(i); \ ++ } \ ++ *Vd = temp; \ ++} ++ ++VEXT2XV(vext2xv_h_b, 16, H, B) ++VEXT2XV(vext2xv_w_b, 32, W, B) ++VEXT2XV(vext2xv_d_b, 64, D, B) ++VEXT2XV(vext2xv_w_h, 32, W, H) ++VEXT2XV(vext2xv_d_h, 64, D, H) ++VEXT2XV(vext2xv_d_w, 64, D, W) ++VEXT2XV(vext2xv_hu_bu, 16, UH, UB) ++VEXT2XV(vext2xv_wu_bu, 32, UW, UB) ++VEXT2XV(vext2xv_du_bu, 64, UD, UB) ++VEXT2XV(vext2xv_wu_hu, 32, UW, UH) ++VEXT2XV(vext2xv_du_hu, 64, UD, UH) ++VEXT2XV(vext2xv_du_wu, 64, UD, UW) ++ ++DO_3OP(vsigncov_b, 8, B, DO_SIGNCOV) ++DO_3OP(vsigncov_h, 16, H, DO_SIGNCOV) ++DO_3OP(vsigncov_w, 32, W, DO_SIGNCOV) ++DO_3OP(vsigncov_d, 64, D, DO_SIGNCOV) ++ ++static uint64_t do_vmskltz_b(int64_t val) ++{ ++ uint64_t m = 0x8080808080808080ULL; ++ uint64_t c = val & m; ++ c |= c << 7; ++ c |= c << 14; ++ c |= c << 28; ++ return c >> 56; ++} ++ ++void HELPER(vmskltz_b)(void *vd, void *vj, uint32_t desc) ++{ ++ int i; ++ uint16_t temp = 0; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ temp = 0; ++ temp = do_vmskltz_b(Vj->D(2 * i)); ++ temp |= (do_vmskltz_b(Vj->D(2 * i + 1)) << 8); ++ Vd->D(2 * i) = temp; ++ Vd->D(2 * i + 1) = 0; ++ } ++} ++ ++static uint64_t do_vmskltz_h(int64_t val) ++{ ++ uint64_t m = 0x8000800080008000ULL; ++ uint64_t c = val & m; ++ c |= c << 15; ++ c |= c << 30; ++ return c >> 60; ++} ++ ++void HELPER(vmskltz_h)(void *vd, void *vj, uint32_t desc) ++{ ++ int i; ++ uint16_t temp = 0; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ temp = 0; ++ temp = do_vmskltz_h(Vj->D(2 * i)); ++ temp |= (do_vmskltz_h(Vj->D(2 * i + 1)) << 4); ++ Vd->D(2 * i) = temp; ++ Vd->D(2 * i + 1) = 0; ++ } ++} ++ ++static uint64_t do_vmskltz_w(int64_t val) ++{ ++ uint64_t m = 0x8000000080000000ULL; ++ uint64_t c = val & m; ++ c |= c << 31; ++ return c >> 62; ++} ++ ++void HELPER(vmskltz_w)(void *vd, void *vj, uint32_t desc) ++{ ++ int i; ++ uint16_t temp = 0; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ temp = 0; ++ temp = do_vmskltz_w(Vj->D(2 * i)); ++ temp |= (do_vmskltz_w(Vj->D(2 * i + 1)) << 2); ++ Vd->D(2 * i) = temp; ++ Vd->D(2 * i + 1) = 0; ++ } ++} ++ ++static uint64_t do_vmskltz_d(int64_t val) ++{ ++ return (uint64_t)val >> 63; ++} ++void HELPER(vmskltz_d)(void *vd, void *vj, uint32_t desc) ++{ ++ int i; ++ uint16_t temp = 0; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ temp = 0; ++ temp = do_vmskltz_d(Vj->D(2 * i)); ++ temp |= (do_vmskltz_d(Vj->D(2 * i + 1)) << 1); ++ Vd->D(2 * i) = temp; ++ Vd->D(2 * i + 1) = 0; ++ } ++} ++ ++void HELPER(vmskgez_b)(void *vd, void *vj, uint32_t desc) ++{ ++ int i; ++ uint16_t temp = 0; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ temp = 0; ++ temp = do_vmskltz_b(Vj->D(2 * i)); ++ temp |= (do_vmskltz_b(Vj->D(2 * i + 1)) << 8); ++ Vd->D(2 * i) = (uint16_t)(~temp); ++ Vd->D(2 * i + 1) = 0; ++ } ++} ++ ++static uint64_t do_vmskez_b(uint64_t a) ++{ ++ uint64_t m = 0x7f7f7f7f7f7f7f7fULL; ++ uint64_t c = ~(((a & m) + m) | a | m); ++ c |= c << 7; ++ c |= c << 14; ++ c |= c << 28; ++ return c >> 56; ++} ++ ++void HELPER(vmsknz_b)(void *vd, void *vj, uint32_t desc) ++{ ++ int i; ++ uint16_t temp = 0; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ temp = 0; ++ temp = do_vmskez_b(Vj->D(2 * i)); ++ temp |= (do_vmskez_b(Vj->D(2 * i + 1)) << 8); ++ Vd->D(2 * i) = (uint16_t)(~temp); ++ Vd->D(2 * i + 1) = 0; ++ } ++} ++ ++void HELPER(vnori_b)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ ++ for (i = 0; i < simd_oprsz(desc); i++) { ++ Vd->B(i) = ~(Vj->B(i) | (uint8_t)imm); ++ } ++} ++ ++#define VSLLWIL(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ typedef __typeof(temp.E1(0)) TD; \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * i) = (TD)Vj->E2(j + ofs * 2 * i) << (imm % BIT); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++ ++void HELPER(vextl_q_d)(void *vd, void *vj, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_makes64(Vj->D(2 * i)); ++ } ++} ++ ++void HELPER(vextl_qu_du)(void *vd, void *vj, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ Vd->Q(i) = int128_make64(Vj->UD(2 * i)); ++ } ++} ++ ++VSLLWIL(vsllwil_h_b, 16, H, B) ++VSLLWIL(vsllwil_w_h, 32, W, H) ++VSLLWIL(vsllwil_d_w, 64, D, W) ++VSLLWIL(vsllwil_hu_bu, 16, UH, UB) ++VSLLWIL(vsllwil_wu_hu, 32, UW, UH) ++VSLLWIL(vsllwil_du_wu, 64, UD, UW) ++ ++#define do_vsrlr(E, T) \ ++static T do_vsrlr_ ##E(T s1, int sh) \ ++{ \ ++ if (sh == 0) { \ ++ return s1; \ ++ } else { \ ++ return (s1 >> sh) + ((s1 >> (sh - 1)) & 0x1); \ ++ } \ ++} ++ ++do_vsrlr(B, uint8_t) ++do_vsrlr(H, uint16_t) ++do_vsrlr(W, uint32_t) ++do_vsrlr(D, uint64_t) ++ ++#define VSRLR(NAME, BIT, T, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = do_vsrlr_ ## E(Vj->E(i), ((T)Vk->E(i))%BIT); \ ++ } \ ++} ++ ++VSRLR(vsrlr_b, 8, uint8_t, B) ++VSRLR(vsrlr_h, 16, uint16_t, H) ++VSRLR(vsrlr_w, 32, uint32_t, W) ++VSRLR(vsrlr_d, 64, uint64_t, D) ++ ++#define VSRLRI(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = do_vsrlr_ ## E(Vj->E(i), imm); \ ++ } \ ++} ++ ++VSRLRI(vsrlri_b, 8, B) ++VSRLRI(vsrlri_h, 16, H) ++VSRLRI(vsrlri_w, 32, W) ++VSRLRI(vsrlri_d, 64, D) ++ ++#define do_vsrar(E, T) \ ++static T do_vsrar_ ##E(T s1, int sh) \ ++{ \ ++ if (sh == 0) { \ ++ return s1; \ ++ } else { \ ++ return (s1 >> sh) + ((s1 >> (sh - 1)) & 0x1); \ ++ } \ ++} ++ ++do_vsrar(B, int8_t) ++do_vsrar(H, int16_t) ++do_vsrar(W, int32_t) ++do_vsrar(D, int64_t) ++ ++#define VSRAR(NAME, BIT, T, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = do_vsrar_ ## E(Vj->E(i), ((T)Vk->E(i))%BIT); \ ++ } \ ++} ++ ++VSRAR(vsrar_b, 8, uint8_t, B) ++VSRAR(vsrar_h, 16, uint16_t, H) ++VSRAR(vsrar_w, 32, uint32_t, W) ++VSRAR(vsrar_d, 64, uint64_t, D) ++ ++#define VSRARI(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = do_vsrar_ ## E(Vj->E(i), imm); \ ++ } \ ++} ++ ++VSRARI(vsrari_b, 8, B) ++VSRARI(vsrari_h, 16, H) ++VSRARI(vsrari_w, 32, W) ++VSRARI(vsrari_d, 64, D) ++ ++#define VSRLN(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = R_SHIFT(Vj->E2(j + ofs * i), \ ++ Vk->E2(j + ofs * i) % BIT); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSRLN(vsrln_b_h, 16, B, UH) ++VSRLN(vsrln_h_w, 32, H, UW) ++VSRLN(vsrln_w_d, 64, W, UD) ++ ++#define VSRAN(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = R_SHIFT(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSRAN(vsran_b_h, 16, B, H, UH) ++VSRAN(vsran_h_w, 32, H, W, UW) ++VSRAN(vsran_w_d, 64, W, D, UD) ++ ++#define VSRLNI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = R_SHIFT(Vj->E2(j + ofs * i), imm); \ ++ temp.E1(j + ofs * (2 * i + 1)) = R_SHIFT(Vd->E2(j + ofs * i), \ ++ imm); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++void HELPER(vsrlni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ ++ for (i = 0; i < 2; i++) { ++ temp.D(2 * i) = int128_getlo(int128_urshift(Vj->Q(i), imm % 128)); ++ temp.D(2 * i +1) = int128_getlo(int128_urshift(Vd->Q(i), imm % 128)); ++ } ++ *Vd = temp; ++} ++ ++VSRLNI(vsrlni_b_h, 16, B, UH) ++VSRLNI(vsrlni_h_w, 32, H, UW) ++VSRLNI(vsrlni_w_d, 64, W, UD) ++ ++#define VSRANI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = R_SHIFT(Vj->E2(j + ofs * i), imm); \ ++ temp.E1(j + ofs * (2 * i + 1)) = R_SHIFT(Vd->E2(j + ofs * i), \ ++ imm); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++void HELPER(vsrani_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ ++ for (i = 0; i < 2; i++) { ++ temp.D(2 * i) = int128_getlo(int128_rshift(Vj->Q(i), imm % 128)); ++ temp.D(2 * i + 1) = int128_getlo(int128_rshift(Vd->Q(i), imm % 128)); ++ } ++ *Vd = temp; ++} ++ ++VSRANI(vsrani_b_h, 16, B, H) ++VSRANI(vsrani_h_w, 32, H, W) ++VSRANI(vsrani_w_d, 64, W, D) ++ ++#define VSRLRN(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = do_vsrlr_ ##E2(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSRLRN(vsrlrn_b_h, 16, B, H, UH) ++VSRLRN(vsrlrn_h_w, 32, H, W, UW) ++VSRLRN(vsrlrn_w_d, 64, W, D, UD) ++ ++#define VSRARN(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = do_vsrar_ ## E2(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSRARN(vsrarn_b_h, 16, B, H, UH) ++VSRARN(vsrarn_h_w, 32, H, W, UW) ++VSRARN(vsrarn_w_d, 64, W, D, UD) ++ ++#define VSRLRNI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = do_vsrlr_ ## E2(Vj->E2(j + ofs * i), imm); \ ++ temp.E1(j + ofs * (2 * i + 1)) = do_vsrlr_ ## E2(Vd->E2(j + ofs * i), \ ++ imm); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++void HELPER(vsrlrni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ Int128 r[4]; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ if (imm == 0) { ++ temp.D(2 * i) = int128_getlo(Vj->Q(i)); ++ temp.D(2 * i + 1) = int128_getlo(Vd->Q(i)); ++ } else { ++ r[2 * i] = int128_and(int128_urshift(Vj->Q(i), (imm - 1)), ++ int128_one()); ++ r[2 * i + 1] = int128_and(int128_urshift(Vd->Q(i), (imm - 1)), ++ int128_one()); ++ temp.D(2 * i) = int128_getlo(int128_add(int128_urshift(Vj->Q(i), ++ imm), r[2 * i])); ++ temp.D(2 * i + 1) = int128_getlo(int128_add(int128_urshift(Vd->Q(i), ++ imm), r[ 2 * i + 1])); ++ } ++ } ++ *Vd = temp; ++} ++ ++VSRLRNI(vsrlrni_b_h, 16, B, H) ++VSRLRNI(vsrlrni_h_w, 32, H, W) ++VSRLRNI(vsrlrni_w_d, 64, W, D) ++ ++#define VSRARNI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = do_vsrar_ ## E2(Vj->E2(j + ofs * i), imm); \ ++ temp.E1(j + ofs * (2 * i + 1)) = do_vsrar_ ## E2(Vd->E2(j + ofs * i), \ ++ imm); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++void HELPER(vsrarni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ Int128 r[4]; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ if (imm == 0) { ++ temp.D(2 * i) = int128_getlo(Vj->Q(i)); ++ temp.D(2 * i + 1) = int128_getlo(Vd->Q(i)); ++ } else { ++ r[2 * i] = int128_and(int128_rshift(Vj->Q(i), (imm - 1)), ++ int128_one()); ++ r[2 * i + 1] = int128_and(int128_rshift(Vd->Q(i), (imm - 1)), ++ int128_one()); ++ temp.D(2 * i) = int128_getlo(int128_add(int128_rshift(Vj->Q(i), ++ imm), r[2 * i])); ++ temp.D(2 * i + 1) = int128_getlo(int128_add(int128_rshift(Vd->Q(i), ++ imm), r[2 * i + 1])); ++ } ++ } ++ *Vd = temp; ++} ++ ++VSRARNI(vsrarni_b_h, 16, B, H) ++VSRARNI(vsrarni_h_w, 32, H, W) ++VSRARNI(vsrarni_w_d, 64, W, D) ++ ++#define SSRLNS(NAME, T1, T2, T3) \ ++static T1 do_ssrlns_ ## NAME(T2 e2, int sa, int sh) \ ++{ \ ++ T1 shft_res; \ ++ if (sa == 0) { \ ++ shft_res = e2; \ ++ } else { \ ++ shft_res = (((T1)e2) >> sa); \ ++ } \ ++ T3 mask; \ ++ mask = (1ull << sh) -1; \ ++ if (shft_res > mask) { \ ++ return mask; \ ++ } else { \ ++ return shft_res; \ ++ } \ ++} ++ ++SSRLNS(B, uint16_t, int16_t, uint8_t) ++SSRLNS(H, uint32_t, int32_t, uint16_t) ++SSRLNS(W, uint64_t, int64_t, uint32_t) ++ ++#define VSSRLN(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = do_ssrlns_ ## E1(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT, \ ++ BIT / 2 - 1); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSSRLN(vssrln_b_h, 16, B, H, UH) ++VSSRLN(vssrln_h_w, 32, H, W, UW) ++VSSRLN(vssrln_w_d, 64, W, D, UD) ++ ++#define SSRANS(E, T1, T2) \ ++static T1 do_ssrans_ ## E(T1 e2, int sa, int sh) \ ++{ \ ++ T1 shft_res; \ ++ if (sa == 0) { \ ++ shft_res = e2; \ ++ } else { \ ++ shft_res = e2 >> sa; \ ++ } \ ++ T2 mask; \ ++ mask = (1ll << sh) - 1; \ ++ if (shft_res > mask) { \ ++ return mask; \ ++ } else if (shft_res < -(mask + 1)) { \ ++ return ~mask; \ ++ } else { \ ++ return shft_res; \ ++ } \ ++} ++ ++SSRANS(B, int16_t, int8_t) ++SSRANS(H, int32_t, int16_t) ++SSRANS(W, int64_t, int32_t) ++ ++#define VSSRAN(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = do_ssrans_ ## E1(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT, \ ++ BIT / 2 - 1); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSSRAN(vssran_b_h, 16, B, H, UH) ++VSSRAN(vssran_h_w, 32, H, W, UW) ++VSSRAN(vssran_w_d, 64, W, D, UD) ++ ++#define SSRLNU(E, T1, T2, T3) \ ++static T1 do_ssrlnu_ ## E(T3 e2, int sa, int sh) \ ++{ \ ++ T1 shft_res; \ ++ if (sa == 0) { \ ++ shft_res = e2; \ ++ } else { \ ++ shft_res = (((T1)e2) >> sa); \ ++ } \ ++ T2 mask; \ ++ mask = (1ull << sh) - 1; \ ++ if (shft_res > mask) { \ ++ return mask; \ ++ } else { \ ++ return shft_res; \ ++ } \ ++} ++ ++SSRLNU(B, uint16_t, uint8_t, int16_t) ++SSRLNU(H, uint32_t, uint16_t, int32_t) ++SSRLNU(W, uint64_t, uint32_t, int64_t) ++ ++#define VSSRLNU(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = do_ssrlnu_ ## E1(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT, \ ++ BIT / 2); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSSRLNU(vssrln_bu_h, 16, B, H, UH) ++VSSRLNU(vssrln_hu_w, 32, H, W, UW) ++VSSRLNU(vssrln_wu_d, 64, W, D, UD) ++ ++#define SSRANU(E, T1, T2, T3) \ ++static T1 do_ssranu_ ## E(T3 e2, int sa, int sh) \ ++{ \ ++ T1 shft_res; \ ++ if (sa == 0) { \ ++ shft_res = e2; \ ++ } else { \ ++ shft_res = e2 >> sa; \ ++ } \ ++ if (e2 < 0) { \ ++ shft_res = 0; \ ++ } \ ++ T2 mask; \ ++ mask = (1ull << sh) - 1; \ ++ if (shft_res > mask) { \ ++ return mask; \ ++ } else { \ ++ return shft_res; \ ++ } \ ++} ++ ++SSRANU(B, uint16_t, uint8_t, int16_t) ++SSRANU(H, uint32_t, uint16_t, int32_t) ++SSRANU(W, uint64_t, uint32_t, int64_t) ++ ++#define VSSRANU(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = do_ssranu_ ## E1(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT, \ ++ BIT / 2); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSSRANU(vssran_bu_h, 16, B, H, UH) ++VSSRANU(vssran_hu_w, 32, H, W, UW) ++VSSRANU(vssran_wu_d, 64, W, D, UD) ++ ++#define VSSRLNI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = do_ssrlns_ ## E1(Vj->E2(j + ofs * i), \ ++ imm, BIT / 2 - 1); \ ++ temp.E1(j + ofs * (2 * i + 1)) = do_ssrlns_ ## E1(Vd->E2(j + ofs * i), \ ++ imm, BIT / 2 - 1); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++static void do_vssrlni_q(VReg *Vd, VReg *Vj, ++ uint64_t imm, int idx, Int128 mask) ++{ ++ Int128 shft_res1, shft_res2; ++ ++ if (imm == 0) { ++ shft_res1 = Vj->Q(idx); ++ shft_res2 = Vd->Q(idx); ++ } else { ++ shft_res1 = int128_urshift(Vj->Q(idx), imm); ++ shft_res2 = int128_urshift(Vd->Q(idx), imm); ++ } ++ ++ if (int128_ult(mask, shft_res1)) { ++ Vd->D(idx * 2) = int128_getlo(mask); ++ }else { ++ Vd->D(idx * 2) = int128_getlo(shft_res1); ++ } ++ ++ if (int128_ult(mask, shft_res2)) { ++ Vd->D(idx * 2 + 1) = int128_getlo(mask); ++ }else { ++ Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); ++ } ++} ++ ++void HELPER(vssrlni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ Int128 mask; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ mask = int128_sub(int128_lshift(int128_one(), 63), int128_one()); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ do_vssrlni_q(Vd, Vj, imm, i, mask); ++ } ++} ++ ++VSSRLNI(vssrlni_b_h, 16, B, H) ++VSSRLNI(vssrlni_h_w, 32, H, W) ++VSSRLNI(vssrlni_w_d, 64, W, D) ++ ++#define VSSRANI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = do_ssrans_ ## E1(Vj->E2(j + ofs * i), \ ++ imm, BIT / 2 - 1); \ ++ temp.E1(j + ofs * (2 * i + 1)) = do_ssrans_ ## E1(Vd->E2(j + ofs * i), \ ++ imm, BIT / 2 - 1); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++static void do_vssrani_d_q(VReg *Vd, VReg *Vj, ++ uint64_t imm, int idx, Int128 mask, Int128 min) ++{ ++ Int128 shft_res1, shft_res2; ++ ++ if (imm == 0) { ++ shft_res1 = Vj->Q(idx); ++ shft_res2 = Vd->Q(idx); ++ } else { ++ shft_res1 = int128_rshift(Vj->Q(idx), imm); ++ shft_res2 = int128_rshift(Vd->Q(idx), imm); ++ } ++ ++ if (int128_gt(shft_res1, mask)) { ++ Vd->D(idx * 2) = int128_getlo(mask); ++ } else if (int128_lt(shft_res1, int128_neg(min))) { ++ Vd->D(idx * 2) = int128_getlo(min); ++ } else { ++ Vd->D(idx * 2) = int128_getlo(shft_res1); ++ } ++ ++ if (int128_gt(shft_res2, mask)) { ++ Vd->D(idx * 2 + 1) = int128_getlo(mask); ++ } else if (int128_lt(shft_res2, int128_neg(min))) { ++ Vd->D(idx * 2 + 1) = int128_getlo(min); ++ } else { ++ Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); ++ } ++} ++ ++void HELPER(vssrani_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ Int128 mask, min; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ mask = int128_sub(int128_lshift(int128_one(), 63), int128_one()); ++ min = int128_lshift(int128_one(), 63); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ do_vssrani_d_q(Vd, Vj, imm, i, mask, min); ++ } ++} ++ ++ ++VSSRANI(vssrani_b_h, 16, B, H) ++VSSRANI(vssrani_h_w, 32, H, W) ++VSSRANI(vssrani_w_d, 64, W, D) ++ ++#define VSSRLNUI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = do_ssrlnu_ ## E1(Vj->E2(j + ofs * i), \ ++ imm, BIT / 2); \ ++ temp.E1(j + ofs * (2 * i + 1)) = do_ssrlnu_ ## E1(Vd->E2(j + ofs * i), \ ++ imm, BIT / 2); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++void HELPER(vssrlni_du_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ Int128 mask; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ mask = int128_sub(int128_lshift(int128_one(), 64), int128_one()); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ do_vssrlni_q(Vd, Vj, imm, i, mask); ++ } ++} ++ ++VSSRLNUI(vssrlni_bu_h, 16, B, H) ++VSSRLNUI(vssrlni_hu_w, 32, H, W) ++VSSRLNUI(vssrlni_wu_d, 64, W, D) ++ ++#define VSSRANUI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = do_ssranu_ ## E1(Vj->E2(j + ofs * i), \ ++ imm, BIT / 2); \ ++ temp.E1(j + ofs * (2 * i + 1)) = do_ssranu_ ## E1(Vd->E2(j + ofs * i), \ ++ imm, BIT / 2); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++static void do_vssrani_du_q(VReg *Vd, VReg *Vj, ++ uint64_t imm, int idx, Int128 mask) ++{ ++ Int128 shft_res1, shft_res2; ++ ++ if (imm == 0) { ++ shft_res1 = Vj->Q(idx); ++ shft_res2 = Vd->Q(idx); ++ } else { ++ shft_res1 = int128_rshift(Vj->Q(idx), imm); ++ shft_res2 = int128_rshift(Vd->Q(idx), imm); ++ } ++ ++ if (int128_lt(Vj->Q(idx), int128_zero())) { ++ shft_res1 = int128_zero(); ++ } ++ ++ if (int128_lt(Vd->Q(idx), int128_zero())) { ++ shft_res2 = int128_zero(); ++ } ++ if (int128_ult(mask, shft_res1)) { ++ Vd->D(idx * 2) = int128_getlo(mask); ++ }else { ++ Vd->D(idx * 2) = int128_getlo(shft_res1); ++ } ++ ++ if (int128_ult(mask, shft_res2)) { ++ Vd->D(idx * 2 + 1) = int128_getlo(mask); ++ }else { ++ Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); ++ } ++ ++} ++ ++void HELPER(vssrani_du_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ Int128 mask; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ mask = int128_sub(int128_lshift(int128_one(), 64), int128_one()); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ do_vssrani_du_q(Vd, Vj, imm, i, mask); ++ } ++} ++ ++VSSRANUI(vssrani_bu_h, 16, B, H) ++VSSRANUI(vssrani_hu_w, 32, H, W) ++VSSRANUI(vssrani_wu_d, 64, W, D) ++ ++#define SSRLRNS(E1, E2, T1, T2, T3) \ ++static T1 do_ssrlrns_ ## E1(T2 e2, int sa, int sh) \ ++{ \ ++ T1 shft_res; \ ++ \ ++ shft_res = do_vsrlr_ ## E2(e2, sa); \ ++ T1 mask; \ ++ mask = (1ull << sh) - 1; \ ++ if (shft_res > mask) { \ ++ return mask; \ ++ } else { \ ++ return shft_res; \ ++ } \ ++} ++ ++SSRLRNS(B, H, uint16_t, int16_t, uint8_t) ++SSRLRNS(H, W, uint32_t, int32_t, uint16_t) ++SSRLRNS(W, D, uint64_t, int64_t, uint32_t) ++ ++#define VSSRLRN(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = do_ssrlrns_ ## E1(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT, \ ++ BIT / 2 - 1); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSSRLRN(vssrlrn_b_h, 16, B, H, UH) ++VSSRLRN(vssrlrn_h_w, 32, H, W, UW) ++VSSRLRN(vssrlrn_w_d, 64, W, D, UD) ++ ++#define SSRARNS(E1, E2, T1, T2) \ ++static T1 do_ssrarns_ ## E1(T1 e2, int sa, int sh) \ ++{ \ ++ T1 shft_res; \ ++ \ ++ shft_res = do_vsrar_ ## E2(e2, sa); \ ++ T2 mask; \ ++ mask = (1ll << sh) - 1; \ ++ if (shft_res > mask) { \ ++ return mask; \ ++ } else if (shft_res < -(mask +1)) { \ ++ return ~mask; \ ++ } else { \ ++ return shft_res; \ ++ } \ ++} ++ ++SSRARNS(B, H, int16_t, int8_t) ++SSRARNS(H, W, int32_t, int16_t) ++SSRARNS(W, D, int64_t, int32_t) ++ ++#define VSSRARN(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = do_ssrarns_ ## E1(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT, \ ++ BIT/ 2 - 1); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSSRARN(vssrarn_b_h, 16, B, H, UH) ++VSSRARN(vssrarn_h_w, 32, H, W, UW) ++VSSRARN(vssrarn_w_d, 64, W, D, UD) ++ ++#define SSRLRNU(E1, E2, T1, T2, T3) \ ++static T1 do_ssrlrnu_ ## E1(T3 e2, int sa, int sh) \ ++{ \ ++ T1 shft_res; \ ++ \ ++ shft_res = do_vsrlr_ ## E2(e2, sa); \ ++ \ ++ T2 mask; \ ++ mask = (1ull << sh) - 1; \ ++ if (shft_res > mask) { \ ++ return mask; \ ++ } else { \ ++ return shft_res; \ ++ } \ ++} ++ ++SSRLRNU(B, H, uint16_t, uint8_t, int16_t) ++SSRLRNU(H, W, uint32_t, uint16_t, int32_t) ++SSRLRNU(W, D, uint64_t, uint32_t, int64_t) ++ ++#define VSSRLRNU(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = do_ssrlrnu_ ## E1(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT, \ ++ BIT / 2); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSSRLRNU(vssrlrn_bu_h, 16, B, H, UH) ++VSSRLRNU(vssrlrn_hu_w, 32, H, W, UW) ++VSSRLRNU(vssrlrn_wu_d, 64, W, D, UD) ++ ++#define SSRARNU(E1, E2, T1, T2, T3) \ ++static T1 do_ssrarnu_ ## E1(T3 e2, int sa, int sh) \ ++{ \ ++ T1 shft_res; \ ++ \ ++ if (e2 < 0) { \ ++ shft_res = 0; \ ++ } else { \ ++ shft_res = do_vsrar_ ## E2(e2, sa); \ ++ } \ ++ T2 mask; \ ++ mask = (1ull << sh) - 1; \ ++ if (shft_res > mask) { \ ++ return mask; \ ++ } else { \ ++ return shft_res; \ ++ } \ ++} ++ ++SSRARNU(B, H, uint16_t, uint8_t, int16_t) ++SSRARNU(H, W, uint32_t, uint16_t, int32_t) ++SSRARNU(W, D, uint64_t, uint32_t, int64_t) ++ ++#define VSSRARNU(NAME, BIT, E1, E2, E3) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ Vd->E1(j + ofs * 2 * i) = do_ssrarnu_ ## E1(Vj->E2(j + ofs * i), \ ++ Vk->E3(j + ofs * i) % BIT, \ ++ BIT / 2); \ ++ } \ ++ Vd->D(2 * i + 1) = 0; \ ++ } \ ++} ++ ++VSSRARNU(vssrarn_bu_h, 16, B, H, UH) ++VSSRARNU(vssrarn_hu_w, 32, H, W, UW) ++VSSRARNU(vssrarn_wu_d, 64, W, D, UD) ++ ++#define VSSRLRNI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = do_ssrlrns_ ## E1(Vj->E2(j + ofs * i), \ ++ imm, BIT / 2 - 1); \ ++ temp.E1(j + ofs * (2 * i + 1)) = do_ssrlrns_ ## E1(Vd->E2(j + ofs * i), \ ++ imm, BIT / 2 - 1); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++static void do_vssrlrni_q(VReg *Vd, VReg * Vj, ++ uint64_t imm, int idx, Int128 mask) ++{ ++ Int128 shft_res1, shft_res2, r1, r2; ++ if (imm == 0) { ++ shft_res1 = Vj->Q(idx); ++ shft_res2 = Vd->Q(idx); ++ } else { ++ r1 = int128_and(int128_urshift(Vj->Q(idx), (imm - 1)), int128_one()); ++ r2 = int128_and(int128_urshift(Vd->Q(idx), (imm - 1)), int128_one()); ++ shft_res1 = (int128_add(int128_urshift(Vj->Q(idx), imm), r1)); ++ shft_res2 = (int128_add(int128_urshift(Vd->Q(idx), imm), r2)); ++ } ++ ++ if (int128_ult(mask, shft_res1)) { ++ Vd->D(idx * 2) = int128_getlo(mask); ++ }else { ++ Vd->D(idx * 2) = int128_getlo(shft_res1); ++ } ++ ++ if (int128_ult(mask, shft_res2)) { ++ Vd->D(idx * 2 + 1) = int128_getlo(mask); ++ }else { ++ Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); ++ } ++} ++ ++void HELPER(vssrlrni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ Int128 mask; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ mask = int128_sub(int128_lshift(int128_one(), 63), int128_one()); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ do_vssrlrni_q(Vd, Vj, imm, i, mask); ++ } ++} ++ ++VSSRLRNI(vssrlrni_b_h, 16, B, H) ++VSSRLRNI(vssrlrni_h_w, 32, H, W) ++VSSRLRNI(vssrlrni_w_d, 64, W, D) ++ ++#define VSSRARNI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = do_ssrarns_ ## E1(Vj->E2(j + ofs * i), \ ++ imm, BIT / 2 - 1); \ ++ temp.E1(j + ofs * (2 * i + 1)) = do_ssrarns_ ## E1(Vd->E2(j + ofs * i), \ ++ imm, BIT / 2 - 1); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++static void do_vssrarni_d_q(VReg *Vd, VReg *Vj, ++ uint64_t imm, int idx, Int128 mask1, Int128 mask2) ++{ ++ Int128 shft_res1, shft_res2, r1, r2; ++ ++ if (imm == 0) { ++ shft_res1 = Vj->Q(idx); ++ shft_res2 = Vd->Q(idx); ++ } else { ++ r1 = int128_and(int128_rshift(Vj->Q(idx), (imm - 1)), int128_one()); ++ r2 = int128_and(int128_rshift(Vd->Q(idx), (imm - 1)), int128_one()); ++ shft_res1 = int128_add(int128_rshift(Vj->Q(idx), imm), r1); ++ shft_res2 = int128_add(int128_rshift(Vd->Q(idx), imm), r2); ++ } ++ if (int128_gt(shft_res1, mask1)) { ++ Vd->D(idx * 2) = int128_getlo(mask1); ++ } else if (int128_lt(shft_res1, int128_neg(mask2))) { ++ Vd->D(idx * 2) = int128_getlo(mask2); ++ } else { ++ Vd->D(idx * 2) = int128_getlo(shft_res1); ++ } ++ ++ if (int128_gt(shft_res2, mask1)) { ++ Vd->D(idx * 2 + 1) = int128_getlo(mask1); ++ } else if (int128_lt(shft_res2, int128_neg(mask2))) { ++ Vd->D(idx * 2 + 1) = int128_getlo(mask2); ++ } else { ++ Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); ++ } ++} ++ ++void HELPER(vssrarni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ Int128 mask1, mask2; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ mask1 = int128_sub(int128_lshift(int128_one(), 63), int128_one()); ++ mask2 = int128_lshift(int128_one(), 63); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ do_vssrarni_d_q(Vd, Vj, imm, i, mask1, mask2); ++ } ++} ++ ++VSSRARNI(vssrarni_b_h, 16, B, H) ++VSSRARNI(vssrarni_h_w, 32, H, W) ++VSSRARNI(vssrarni_w_d, 64, W, D) ++ ++#define VSSRLRNUI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = do_ssrlrnu_ ## E1(Vj->E2(j + ofs * i), \ ++ imm, BIT / 2); \ ++ temp.E1(j + ofs * (2 * i + 1)) = do_ssrlrnu_ ## E1(Vd->E2(j + ofs * i), \ ++ imm, BIT / 2); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++void HELPER(vssrlrni_du_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ Int128 mask; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ mask = int128_sub(int128_lshift(int128_one(), 64), int128_one()); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ do_vssrlrni_q(Vd, Vj, imm, i, mask); ++ } ++} ++ ++VSSRLRNUI(vssrlrni_bu_h, 16, B, H) ++VSSRLRNUI(vssrlrni_hu_w, 32, H, W) ++VSSRLRNUI(vssrlrni_wu_d, 64, W, D) ++ ++#define VSSRARNUI(NAME, BIT, E1, E2) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E1(j + ofs * 2 * i) = do_ssrarnu_ ## E1(Vj->E2(j + ofs * i), \ ++ imm, BIT / 2); \ ++ temp.E1(j + ofs * (2 * i + 1)) = do_ssrarnu_ ## E1(Vd->E2(j + ofs * i), \ ++ imm, BIT / 2); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++static void do_vssrarni_du_q(VReg *Vd, VReg *Vj, ++ uint64_t imm, int idx, Int128 mask1, Int128 mask2) ++{ ++ Int128 shft_res1, shft_res2, r1, r2; ++ ++ if (imm == 0) { ++ shft_res1 = Vj->Q(idx); ++ shft_res2 = Vd->Q(idx); ++ } else { ++ r1 = int128_and(int128_rshift(Vj->Q(idx), (imm - 1)), int128_one()); ++ r2 = int128_and(int128_rshift(Vd->Q(idx), (imm - 1)), int128_one()); ++ shft_res1 = int128_add(int128_rshift(Vj->Q(idx), imm), r1); ++ shft_res2 = int128_add(int128_rshift(Vd->Q(idx), imm), r2); ++ } ++ ++ if (int128_lt(Vj->Q(idx), int128_zero())) { ++ shft_res1 = int128_zero(); ++ } ++ if (int128_lt(Vd->Q(idx), int128_zero())) { ++ shft_res2 = int128_zero(); ++ } ++ ++ if (int128_gt(shft_res1, mask1)) { ++ Vd->D(idx * 2) = int128_getlo(mask1); ++ } else if (int128_lt(shft_res1, int128_neg(mask2))) { ++ Vd->D(idx * 2) = int128_getlo(mask2); ++ } else { ++ Vd->D(idx * 2) = int128_getlo(shft_res1); ++ } ++ ++ if (int128_gt(shft_res2, mask1)) { ++ Vd->D(idx * 2 + 1) = int128_getlo(mask1); ++ } else if (int128_lt(shft_res2, int128_neg(mask2))) { ++ Vd->D(idx * 2 + 1) = int128_getlo(mask2); ++ } else { ++ Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); ++ } ++} ++ ++void HELPER(vssrarni_du_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ Int128 mask1, mask2; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ mask1 = int128_sub(int128_lshift(int128_one(), 64), int128_one()); ++ mask2 = int128_lshift(int128_one(), 64); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ do_vssrarni_du_q(Vd, Vj, imm, i, mask1, mask2); ++ } ++} ++ ++VSSRARNUI(vssrarni_bu_h, 16, B, H) ++VSSRARNUI(vssrarni_hu_w, 32, H, W) ++VSSRARNUI(vssrarni_wu_d, 64, W, D) ++ ++#define DO_2OP(NAME, BIT, E, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) \ ++ { \ ++ Vd->E(i) = DO_OP(Vj->E(i)); \ ++ } \ ++} ++ ++DO_2OP(vclo_b, 8, UB, DO_CLO_B) ++DO_2OP(vclo_h, 16, UH, DO_CLO_H) ++DO_2OP(vclo_w, 32, UW, DO_CLO_W) ++DO_2OP(vclo_d, 64, UD, DO_CLO_D) ++DO_2OP(vclz_b, 8, UB, DO_CLZ_B) ++DO_2OP(vclz_h, 16, UH, DO_CLZ_H) ++DO_2OP(vclz_w, 32, UW, DO_CLZ_W) ++DO_2OP(vclz_d, 64, UD, DO_CLZ_D) ++ ++#define VPCNT(NAME, BIT, E, FN) \ ++void HELPER(NAME)(void *vd, void *vj, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) \ ++ { \ ++ Vd->E(i) = FN(Vj->E(i)); \ ++ } \ ++} ++ ++VPCNT(vpcnt_b, 8, UB, ctpop8) ++VPCNT(vpcnt_h, 16, UH, ctpop16) ++VPCNT(vpcnt_w, 32, UW, ctpop32) ++VPCNT(vpcnt_d, 64, UD, ctpop64) ++ ++#define DO_BIT(NAME, BIT, E, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = DO_OP(Vj->E(i), Vk->E(i)%BIT); \ ++ } \ ++} ++ ++DO_BIT(vbitclr_b, 8, UB, DO_BITCLR) ++DO_BIT(vbitclr_h, 16, UH, DO_BITCLR) ++DO_BIT(vbitclr_w, 32, UW, DO_BITCLR) ++DO_BIT(vbitclr_d, 64, UD, DO_BITCLR) ++DO_BIT(vbitset_b, 8, UB, DO_BITSET) ++DO_BIT(vbitset_h, 16, UH, DO_BITSET) ++DO_BIT(vbitset_w, 32, UW, DO_BITSET) ++DO_BIT(vbitset_d, 64, UD, DO_BITSET) ++DO_BIT(vbitrev_b, 8, UB, DO_BITREV) ++DO_BIT(vbitrev_h, 16, UH, DO_BITREV) ++DO_BIT(vbitrev_w, 32, UW, DO_BITREV) ++DO_BIT(vbitrev_d, 64, UD, DO_BITREV) ++ ++#define DO_BITI(NAME, BIT, E, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = DO_OP(Vj->E(i), imm); \ ++ } \ ++} ++ ++DO_BITI(vbitclri_b, 8, UB, DO_BITCLR) ++DO_BITI(vbitclri_h, 16, UH, DO_BITCLR) ++DO_BITI(vbitclri_w, 32, UW, DO_BITCLR) ++DO_BITI(vbitclri_d, 64, UD, DO_BITCLR) ++DO_BITI(vbitseti_b, 8, UB, DO_BITSET) ++DO_BITI(vbitseti_h, 16, UH, DO_BITSET) ++DO_BITI(vbitseti_w, 32, UW, DO_BITSET) ++DO_BITI(vbitseti_d, 64, UD, DO_BITSET) ++DO_BITI(vbitrevi_b, 8, UB, DO_BITREV) ++DO_BITI(vbitrevi_h, 16, UH, DO_BITREV) ++DO_BITI(vbitrevi_w, 32, UW, DO_BITREV) ++DO_BITI(vbitrevi_d, 64, UD, DO_BITREV) ++ ++#define VFRSTP(NAME, BIT, MASK, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, m, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ m = Vk->E(i * ofs) & MASK; \ ++ for (j = 0; j < ofs; j++) { \ ++ if (Vj->E(j + ofs * i) < 0) { \ ++ break; \ ++ } \ ++ } \ ++ Vd->E(m + i * ofs) = j; \ ++ } \ ++} ++ ++VFRSTP(vfrstp_b, 8, 0xf, B) ++VFRSTP(vfrstp_h, 16, 0x7, H) ++ ++#define VFRSTPI(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, m, ofs; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ m = imm % ofs; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ if (Vj->E(j + ofs * i) < 0) { \ ++ break; \ ++ } \ ++ } \ ++ Vd->E(m + i * ofs) = j; \ ++ } \ ++} ++ ++VFRSTPI(vfrstpi_b, 8, B) ++VFRSTPI(vfrstpi_h, 16, H) ++ ++static void vec_update_fcsr0_mask(CPULoongArchState *env, ++ uintptr_t pc, int mask) ++{ ++ int flags = get_float_exception_flags(&env->fp_status); ++ ++ set_float_exception_flags(0, &env->fp_status); ++ ++ flags &= ~mask; ++ ++ if (flags) { ++ flags = ieee_ex_to_loongarch(flags); ++ UPDATE_FP_CAUSE(env->fcsr0, flags); ++ } ++ ++ if (GET_FP_ENABLES(env->fcsr0) & flags) { ++ do_raise_exception(env, EXCCODE_FPE, pc); ++ } else { ++ UPDATE_FP_FLAGS(env->fcsr0, flags); ++ } ++} ++ ++static void vec_update_fcsr0(CPULoongArchState *env, uintptr_t pc) ++{ ++ vec_update_fcsr0_mask(env, pc, 0); ++} ++ ++static inline void vec_clear_cause(CPULoongArchState *env) ++{ ++ SET_FP_CAUSE(env->fcsr0, 0); ++} ++ ++#define DO_3OP_F(NAME, BIT, E, FN) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, \ ++ CPULoongArchState *env, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ vec_clear_cause(env); \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = FN(Vj->E(i), Vk->E(i), &env->fp_status); \ ++ vec_update_fcsr0(env, GETPC()); \ ++ } \ ++} ++ ++DO_3OP_F(vfadd_s, 32, UW, float32_add) ++DO_3OP_F(vfadd_d, 64, UD, float64_add) ++DO_3OP_F(vfsub_s, 32, UW, float32_sub) ++DO_3OP_F(vfsub_d, 64, UD, float64_sub) ++DO_3OP_F(vfmul_s, 32, UW, float32_mul) ++DO_3OP_F(vfmul_d, 64, UD, float64_mul) ++DO_3OP_F(vfdiv_s, 32, UW, float32_div) ++DO_3OP_F(vfdiv_d, 64, UD, float64_div) ++DO_3OP_F(vfmax_s, 32, UW, float32_maxnum) ++DO_3OP_F(vfmax_d, 64, UD, float64_maxnum) ++DO_3OP_F(vfmin_s, 32, UW, float32_minnum) ++DO_3OP_F(vfmin_d, 64, UD, float64_minnum) ++DO_3OP_F(vfmaxa_s, 32, UW, float32_maxnummag) ++DO_3OP_F(vfmaxa_d, 64, UD, float64_maxnummag) ++DO_3OP_F(vfmina_s, 32, UW, float32_minnummag) ++DO_3OP_F(vfmina_d, 64, UD, float64_minnummag) ++ ++#define DO_4OP_F(NAME, BIT, E, FN, flags) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, void *va, \ ++ CPULoongArchState *env, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ VReg *Va = (VReg *)va; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ vec_clear_cause(env); \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = FN(Vj->E(i), Vk->E(i), Va->E(i), flags, &env->fp_status); \ ++ vec_update_fcsr0(env, GETPC()); \ ++ } \ ++} ++ ++DO_4OP_F(vfmadd_s, 32, UW, float32_muladd, 0) ++DO_4OP_F(vfmadd_d, 64, UD, float64_muladd, 0) ++DO_4OP_F(vfmsub_s, 32, UW, float32_muladd, float_muladd_negate_c) ++DO_4OP_F(vfmsub_d, 64, UD, float64_muladd, float_muladd_negate_c) ++DO_4OP_F(vfnmadd_s, 32, UW, float32_muladd, float_muladd_negate_result) ++DO_4OP_F(vfnmadd_d, 64, UD, float64_muladd, float_muladd_negate_result) ++DO_4OP_F(vfnmsub_s, 32, UW, float32_muladd, ++ float_muladd_negate_c | float_muladd_negate_result) ++DO_4OP_F(vfnmsub_d, 64, UD, float64_muladd, ++ float_muladd_negate_c | float_muladd_negate_result) ++ ++#define DO_2OP_F(NAME, BIT, E, FN) \ ++void HELPER(NAME)(void *vd, void *vj, \ ++ CPULoongArchState *env, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ vec_clear_cause(env); \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = FN(env, Vj->E(i)); \ ++ } \ ++} ++ ++#define FLOGB(BIT, T) \ ++static T do_flogb_## BIT(CPULoongArchState *env, T fj) \ ++{ \ ++ T fp, fd; \ ++ float_status *status = &env->fp_status; \ ++ FloatRoundMode old_mode = get_float_rounding_mode(status); \ ++ \ ++ set_float_rounding_mode(float_round_down, status); \ ++ fp = float ## BIT ##_log2(fj, status); \ ++ fd = float ## BIT ##_round_to_int(fp, status); \ ++ set_float_rounding_mode(old_mode, status); \ ++ vec_update_fcsr0_mask(env, GETPC(), float_flag_inexact); \ ++ return fd; \ ++} ++ ++FLOGB(32, uint32_t) ++FLOGB(64, uint64_t) ++ ++#define FCLASS(NAME, BIT, E, FN) \ ++void HELPER(NAME)(void *vd, void *vj, \ ++ CPULoongArchState *env, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = FN(env, Vj->E(i)); \ ++ } \ ++} ++ ++FCLASS(vfclass_s, 32, UW, helper_fclass_s) ++FCLASS(vfclass_d, 64, UD, helper_fclass_d) ++ ++#define FSQRT(BIT, T) \ ++static T do_fsqrt_## BIT(CPULoongArchState *env, T fj) \ ++{ \ ++ T fd; \ ++ fd = float ## BIT ##_sqrt(fj, &env->fp_status); \ ++ vec_update_fcsr0(env, GETPC()); \ ++ return fd; \ ++} ++ ++FSQRT(32, uint32_t) ++FSQRT(64, uint64_t) ++ ++#define FRECIP(BIT, T) \ ++static T do_frecip_## BIT(CPULoongArchState *env, T fj) \ ++{ \ ++ T fd; \ ++ fd = float ## BIT ##_div(float ## BIT ##_one, fj, &env->fp_status); \ ++ vec_update_fcsr0(env, GETPC()); \ ++ return fd; \ ++} ++ ++FRECIP(32, uint32_t) ++FRECIP(64, uint64_t) ++ ++#define FRSQRT(BIT, T) \ ++static T do_frsqrt_## BIT(CPULoongArchState *env, T fj) \ ++{ \ ++ T fd, fp; \ ++ fp = float ## BIT ##_sqrt(fj, &env->fp_status); \ ++ fd = float ## BIT ##_div(float ## BIT ##_one, fp, &env->fp_status); \ ++ vec_update_fcsr0(env, GETPC()); \ ++ return fd; \ ++} ++ ++FRSQRT(32, uint32_t) ++FRSQRT(64, uint64_t) ++ ++DO_2OP_F(vflogb_s, 32, UW, do_flogb_32) ++DO_2OP_F(vflogb_d, 64, UD, do_flogb_64) ++DO_2OP_F(vfsqrt_s, 32, UW, do_fsqrt_32) ++DO_2OP_F(vfsqrt_d, 64, UD, do_fsqrt_64) ++DO_2OP_F(vfrecip_s, 32, UW, do_frecip_32) ++DO_2OP_F(vfrecip_d, 64, UD, do_frecip_64) ++DO_2OP_F(vfrsqrt_s, 32, UW, do_frsqrt_32) ++DO_2OP_F(vfrsqrt_d, 64, UD, do_frsqrt_64) ++ ++static uint32_t float16_cvt_float32(uint16_t h, float_status *status) ++{ ++ return float16_to_float32(h, true, status); ++} ++static uint64_t float32_cvt_float64(uint32_t s, float_status *status) ++{ ++ return float32_to_float64(s, status); ++} ++ ++static uint16_t float32_cvt_float16(uint32_t s, float_status *status) ++{ ++ return float32_to_float16(s, true, status); ++} ++static uint32_t float64_cvt_float32(uint64_t d, float_status *status) ++{ ++ return float64_to_float32(d, status); ++} ++ ++void HELPER(vfcvtl_s_h)(void *vd, void *vj, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i, j, ofs; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ ofs = LSX_LEN / 32; ++ vec_clear_cause(env); ++ for (i = 0; i < oprsz / 16; i++) { ++ for (j = 0; j < ofs; j++) { ++ temp.UW(j + ofs * i) =float16_cvt_float32(Vj->UH(j + ofs * 2 * i), ++ &env->fp_status); ++ } ++ vec_update_fcsr0(env, GETPC()); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vfcvtl_d_s)(void *vd, void *vj, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i, j, ofs; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ ofs = LSX_LEN / 64; ++ vec_clear_cause(env); ++ for (i = 0; i < oprsz / 16; i++) { ++ for (j = 0; j < ofs; j++) { ++ temp.UD(j + ofs * i) = float32_cvt_float64(Vj->UW(j + ofs * 2 * i), ++ &env->fp_status); ++ } ++ vec_update_fcsr0(env, GETPC()); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vfcvth_s_h)(void *vd, void *vj, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i, j, ofs; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ ofs = LSX_LEN / 32; ++ vec_clear_cause(env); ++ for (i = 0; i < oprsz / 16; i++) { ++ for (j = 0; j < ofs; j++) { ++ temp.UW(j + ofs * i) = float16_cvt_float32(Vj->UH(j + ofs * (2 * i + 1)), ++ &env->fp_status); ++ } ++ vec_update_fcsr0(env, GETPC()); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vfcvth_d_s)(void *vd, void *vj, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i, j, ofs; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ ofs = LSX_LEN / 64; ++ vec_clear_cause(env); ++ for (i = 0; i < oprsz / 16; i++) { ++ for (j = 0; j < ofs; j++) { ++ temp.UD(j + ofs * i) = float32_cvt_float64(Vj->UW(j + ofs * (2 * i + 1)), ++ &env->fp_status); ++ } ++ vec_update_fcsr0(env, GETPC()); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vfcvt_h_s)(void *vd, void *vj, void *vk, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i, j, ofs; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ ofs = LSX_LEN / 32; ++ vec_clear_cause(env); ++ for(i = 0; i < oprsz / 16; i++) { ++ for (j = 0; j < ofs; j++) { ++ temp.UH(j + ofs * (2 * i + 1)) = float32_cvt_float16(Vj->UW(j + ofs * i), ++ &env->fp_status); ++ temp.UH(j + ofs * 2 * i) = float32_cvt_float16(Vk->UW(j + ofs * i), ++ &env->fp_status); ++ } ++ vec_update_fcsr0(env, GETPC()); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vfcvt_s_d)(void *vd, void *vj, void *vk, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i, j, ofs; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ ofs = LSX_LEN / 64; ++ vec_clear_cause(env); ++ for(i = 0; i < oprsz / 16; i++) { ++ for (j = 0; j < ofs; j++) { ++ temp.UW(j + ofs * (2 * i + 1)) = float64_cvt_float32(Vj->UD(j + ofs * i), ++ &env->fp_status); ++ temp.UW(j + ofs * 2 * i) = float64_cvt_float32(Vk->UD(j + ofs * i), ++ &env->fp_status); ++ } ++ vec_update_fcsr0(env, GETPC()); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vfrint_s)(void *vd, void *vj, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ vec_clear_cause(env); ++ for (i = 0; i < oprsz / 4; i++) { ++ Vd->W(i) = float32_round_to_int(Vj->UW(i), &env->fp_status); ++ vec_update_fcsr0(env, GETPC()); ++ } ++} ++ ++void HELPER(vfrint_d)(void *vd, void *vj, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ vec_clear_cause(env); ++ for (i = 0; i < oprsz / 8; i++) { ++ Vd->D(i) = float64_round_to_int(Vj->UD(i), &env->fp_status); ++ vec_update_fcsr0(env, GETPC()); ++ } ++} ++ ++#define FCVT_2OP(NAME, BIT, E, MODE) \ ++void HELPER(NAME)(void *vd, void *vj, \ ++ CPULoongArchState *env, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ vec_clear_cause(env); \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); \ ++ set_float_rounding_mode(MODE, &env->fp_status); \ ++ Vd->E(i) = float## BIT ## _round_to_int(Vj->E(i), &env->fp_status); \ ++ set_float_rounding_mode(old_mode, &env->fp_status); \ ++ vec_update_fcsr0(env, GETPC()); \ ++ } \ ++} ++ ++FCVT_2OP(vfrintrne_s, 32, UW, float_round_nearest_even) ++FCVT_2OP(vfrintrne_d, 64, UD, float_round_nearest_even) ++FCVT_2OP(vfrintrz_s, 32, UW, float_round_to_zero) ++FCVT_2OP(vfrintrz_d, 64, UD, float_round_to_zero) ++FCVT_2OP(vfrintrp_s, 32, UW, float_round_up) ++FCVT_2OP(vfrintrp_d, 64, UD, float_round_up) ++FCVT_2OP(vfrintrm_s, 32, UW, float_round_down) ++FCVT_2OP(vfrintrm_d, 64, UD, float_round_down) ++ ++#define FTINT(NAME, FMT1, FMT2, T1, T2, MODE) \ ++static T2 do_ftint ## NAME(CPULoongArchState *env, T1 fj) \ ++{ \ ++ T2 fd; \ ++ FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); \ ++ \ ++ set_float_rounding_mode(MODE, &env->fp_status); \ ++ fd = do_## FMT1 ##_to_## FMT2(env, fj); \ ++ set_float_rounding_mode(old_mode, &env->fp_status); \ ++ return fd; \ ++} ++ ++#define DO_FTINT(FMT1, FMT2, T1, T2) \ ++static T2 do_## FMT1 ##_to_## FMT2(CPULoongArchState *env, T1 fj) \ ++{ \ ++ T2 fd; \ ++ \ ++ fd = FMT1 ##_to_## FMT2(fj, &env->fp_status); \ ++ if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { \ ++ if (FMT1 ##_is_any_nan(fj)) { \ ++ fd = 0; \ ++ } \ ++ } \ ++ vec_update_fcsr0(env, GETPC()); \ ++ return fd; \ ++} ++ ++DO_FTINT(float32, int32, uint32_t, uint32_t) ++DO_FTINT(float64, int64, uint64_t, uint64_t) ++DO_FTINT(float32, uint32, uint32_t, uint32_t) ++DO_FTINT(float64, uint64, uint64_t, uint64_t) ++DO_FTINT(float64, int32, uint64_t, uint32_t) ++DO_FTINT(float32, int64, uint32_t, uint64_t) ++ ++FTINT(rne_w_s, float32, int32, uint32_t, uint32_t, float_round_nearest_even) ++FTINT(rne_l_d, float64, int64, uint64_t, uint64_t, float_round_nearest_even) ++FTINT(rp_w_s, float32, int32, uint32_t, uint32_t, float_round_up) ++FTINT(rp_l_d, float64, int64, uint64_t, uint64_t, float_round_up) ++FTINT(rz_w_s, float32, int32, uint32_t, uint32_t, float_round_to_zero) ++FTINT(rz_l_d, float64, int64, uint64_t, uint64_t, float_round_to_zero) ++FTINT(rm_w_s, float32, int32, uint32_t, uint32_t, float_round_down) ++FTINT(rm_l_d, float64, int64, uint64_t, uint64_t, float_round_down) ++ ++DO_2OP_F(vftintrne_w_s, 32, UW, do_ftintrne_w_s) ++DO_2OP_F(vftintrne_l_d, 64, UD, do_ftintrne_l_d) ++DO_2OP_F(vftintrp_w_s, 32, UW, do_ftintrp_w_s) ++DO_2OP_F(vftintrp_l_d, 64, UD, do_ftintrp_l_d) ++DO_2OP_F(vftintrz_w_s, 32, UW, do_ftintrz_w_s) ++DO_2OP_F(vftintrz_l_d, 64, UD, do_ftintrz_l_d) ++DO_2OP_F(vftintrm_w_s, 32, UW, do_ftintrm_w_s) ++DO_2OP_F(vftintrm_l_d, 64, UD, do_ftintrm_l_d) ++DO_2OP_F(vftint_w_s, 32, UW, do_float32_to_int32) ++DO_2OP_F(vftint_l_d, 64, UD, do_float64_to_int64) ++ ++FTINT(rz_wu_s, float32, uint32, uint32_t, uint32_t, float_round_to_zero) ++FTINT(rz_lu_d, float64, uint64, uint64_t, uint64_t, float_round_to_zero) ++ ++DO_2OP_F(vftintrz_wu_s, 32, UW, do_ftintrz_wu_s) ++DO_2OP_F(vftintrz_lu_d, 64, UD, do_ftintrz_lu_d) ++DO_2OP_F(vftint_wu_s, 32, UW, do_float32_to_uint32) ++DO_2OP_F(vftint_lu_d, 64, UD, do_float64_to_uint64) ++ ++FTINT(rm_w_d, float64, int32, uint64_t, uint32_t, float_round_down) ++FTINT(rp_w_d, float64, int32, uint64_t, uint32_t, float_round_up) ++FTINT(rz_w_d, float64, int32, uint64_t, uint32_t, float_round_to_zero) ++FTINT(rne_w_d, float64, int32, uint64_t, uint32_t, float_round_nearest_even) ++ ++#define FTINT_W_D(NAME, FN) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, \ ++ CPULoongArchState *env, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / 64; \ ++ vec_clear_cause(env); \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.W(j + ofs * (2 * i + 1)) = FN(env, Vj->UD(j + ofs * i)); \ ++ temp.W(j + ofs * 2 * i) = FN(env, Vk->UD(j + ofs * i)); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++FTINT_W_D(vftint_w_d, do_float64_to_int32) ++FTINT_W_D(vftintrm_w_d, do_ftintrm_w_d) ++FTINT_W_D(vftintrp_w_d, do_ftintrp_w_d) ++FTINT_W_D(vftintrz_w_d, do_ftintrz_w_d) ++FTINT_W_D(vftintrne_w_d, do_ftintrne_w_d) ++ ++FTINT(rml_l_s, float32, int64, uint32_t, uint64_t, float_round_down) ++FTINT(rpl_l_s, float32, int64, uint32_t, uint64_t, float_round_up) ++FTINT(rzl_l_s, float32, int64, uint32_t, uint64_t, float_round_to_zero) ++FTINT(rnel_l_s, float32, int64, uint32_t, uint64_t, float_round_nearest_even) ++FTINT(rmh_l_s, float32, int64, uint32_t, uint64_t, float_round_down) ++FTINT(rph_l_s, float32, int64, uint32_t, uint64_t, float_round_up) ++FTINT(rzh_l_s, float32, int64, uint32_t, uint64_t, float_round_to_zero) ++FTINT(rneh_l_s, float32, int64, uint32_t, uint64_t, float_round_nearest_even) ++ ++#define FTINTL_L_S(NAME, FN) \ ++void HELPER(NAME)(void *vd, void *vj, \ ++ CPULoongArchState *env, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / 64; \ ++ vec_clear_cause(env); \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.D(j + ofs * i) = FN(env, Vj->UW(j + ofs * 2 * i)); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++FTINTL_L_S(vftintl_l_s, do_float32_to_int64) ++FTINTL_L_S(vftintrml_l_s, do_ftintrml_l_s) ++FTINTL_L_S(vftintrpl_l_s, do_ftintrpl_l_s) ++FTINTL_L_S(vftintrzl_l_s, do_ftintrzl_l_s) ++FTINTL_L_S(vftintrnel_l_s, do_ftintrnel_l_s) ++ ++#define FTINTH_L_S(NAME, FN) \ ++void HELPER(NAME)(void *vd, void *vj, \ ++ CPULoongArchState *env, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / 64; \ ++ vec_clear_cause(env); \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.D(j + ofs * i) = FN(env, Vj->UW(j + ofs * (2 * i + 1))); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++FTINTH_L_S(vftinth_l_s, do_float32_to_int64) ++FTINTH_L_S(vftintrmh_l_s, do_ftintrmh_l_s) ++FTINTH_L_S(vftintrph_l_s, do_ftintrph_l_s) ++FTINTH_L_S(vftintrzh_l_s, do_ftintrzh_l_s) ++FTINTH_L_S(vftintrneh_l_s, do_ftintrneh_l_s) ++ ++#define FFINT(NAME, FMT1, FMT2, T1, T2) \ ++static T2 do_ffint_ ## NAME(CPULoongArchState *env, T1 fj) \ ++{ \ ++ T2 fd; \ ++ \ ++ fd = FMT1 ##_to_## FMT2(fj, &env->fp_status); \ ++ vec_update_fcsr0(env, GETPC()); \ ++ return fd; \ ++} ++ ++FFINT(s_w, int32, float32, int32_t, uint32_t) ++FFINT(d_l, int64, float64, int64_t, uint64_t) ++FFINT(s_wu, uint32, float32, uint32_t, uint32_t) ++FFINT(d_lu, uint64, float64, uint64_t, uint64_t) ++ ++DO_2OP_F(vffint_s_w, 32, W, do_ffint_s_w) ++DO_2OP_F(vffint_d_l, 64, D, do_ffint_d_l) ++DO_2OP_F(vffint_s_wu, 32, UW, do_ffint_s_wu) ++DO_2OP_F(vffint_d_lu, 64, UD, do_ffint_d_lu) ++ ++void HELPER(vffintl_d_w)(void *vd, void *vj, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i, j, ofs; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ ofs = LSX_LEN / 64; ++ vec_clear_cause(env); ++ for (i = 0; i < oprsz / 16; i++) { ++ for (j = 0; j < ofs; j++) { ++ temp.D(j + ofs * i) = int32_to_float64(Vj->W(j + ofs * 2 * i), ++ &env->fp_status); ++ } ++ vec_update_fcsr0(env, GETPC()); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vffinth_d_w)(void *vd, void *vj, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i, j, ofs; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ ofs = LSX_LEN / 64; ++ vec_clear_cause(env); ++ for (i = 0; i < oprsz /16; i++) { ++ for (j = 0; j < ofs; j++) { ++ temp.D(j + ofs * i) = int32_to_float64(Vj->W(j + ofs * (2 * i + 1)), ++ &env->fp_status); ++ } ++ vec_update_fcsr0(env, GETPC()); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vffint_s_l)(void *vd, void *vj, void *vk, ++ CPULoongArchState *env, uint32_t desc) ++{ ++ int i, j, ofs; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ int oprsz = simd_oprsz(desc); ++ ++ ofs = LSX_LEN / 64; ++ vec_clear_cause(env); ++ for (i = 0; i < oprsz / 16; i++) { ++ for (j = 0; j < ofs; j++) { ++ temp.W(j + ofs * (2 * i + 1)) = int64_to_float32(Vj->D(j + ofs * i), ++ &env->fp_status); ++ temp.W(j + ofs * 2 * i) = int64_to_float32(Vk->D(j + ofs * i), ++ &env->fp_status); ++ } ++ vec_update_fcsr0(env, GETPC()); ++ } ++ *Vd = temp; ++} ++ ++#define VCMPI(NAME, BIT, E, DO_OP) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ typedef __typeof(Vd->E(0)) TD; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = DO_OP(Vj->E(i), (TD)imm); \ ++ } \ ++} ++ ++VCMPI(vseqi_b, 8, B, VSEQ) ++VCMPI(vseqi_h, 16, H, VSEQ) ++VCMPI(vseqi_w, 32, W, VSEQ) ++VCMPI(vseqi_d, 64, D, VSEQ) ++VCMPI(vslei_b, 8, B, VSLE) ++VCMPI(vslei_h, 16, H, VSLE) ++VCMPI(vslei_w, 32, W, VSLE) ++VCMPI(vslei_d, 64, D, VSLE) ++VCMPI(vslei_bu, 8, UB, VSLE) ++VCMPI(vslei_hu, 16, UH, VSLE) ++VCMPI(vslei_wu, 32, UW, VSLE) ++VCMPI(vslei_du, 64, UD, VSLE) ++VCMPI(vslti_b, 8, B, VSLT) ++VCMPI(vslti_h, 16, H, VSLT) ++VCMPI(vslti_w, 32, W, VSLT) ++VCMPI(vslti_d, 64, D, VSLT) ++VCMPI(vslti_bu, 8, UB, VSLT) ++VCMPI(vslti_hu, 16, UH, VSLT) ++VCMPI(vslti_wu, 32, UW, VSLT) ++VCMPI(vslti_du, 64, UD, VSLT) ++ ++static uint64_t vfcmp_common(CPULoongArchState *env, ++ FloatRelation cmp, uint32_t flags) ++{ ++ uint64_t ret = 0; ++ ++ switch (cmp) { ++ case float_relation_less: ++ ret = (flags & FCMP_LT); ++ break; ++ case float_relation_equal: ++ ret = (flags & FCMP_EQ); ++ break; ++ case float_relation_greater: ++ ret = (flags & FCMP_GT); ++ break; ++ case float_relation_unordered: ++ ret = (flags & FCMP_UN); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ ++ if (ret) { ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++#define VFCMP(NAME, BIT, E, FN) \ ++void HELPER(NAME)(CPULoongArchState *env, uint32_t oprsz, \ ++ uint32_t vd, uint32_t vj, uint32_t vk, uint32_t flags) \ ++{ \ ++ int i; \ ++ VReg t; \ ++ VReg *Vd = &(env->fpr[vd].vreg); \ ++ VReg *Vj = &(env->fpr[vj].vreg); \ ++ VReg *Vk = &(env->fpr[vk].vreg); \ ++ \ ++ vec_clear_cause(env); \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ FloatRelation cmp; \ ++ cmp = FN(Vj->E(i), Vk->E(i), &env->fp_status); \ ++ t.E(i) = vfcmp_common(env, cmp, flags); \ ++ vec_update_fcsr0(env, GETPC()); \ ++ } \ ++ *Vd = t; \ ++} ++ ++VFCMP(vfcmp_c_s, 32, UW, float32_compare_quiet) ++VFCMP(vfcmp_s_s, 32, UW, float32_compare) ++VFCMP(vfcmp_c_d, 64, UD, float64_compare_quiet) ++VFCMP(vfcmp_s_d, 64, UD, float64_compare) ++ ++void HELPER(vbitseli_b)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ ++ for (i = 0; i < simd_oprsz(desc); i++) { ++ Vd->B(i) = (~Vd->B(i) & Vj->B(i)) | (Vd->B(i) & imm); ++ } ++} ++ ++/* Copy from target/arm/tcg/sve_helper.c */ ++static inline bool do_match2(uint64_t n, uint64_t m0, uint64_t m1, int esz) ++{ ++ int bits = 8 << esz; ++ uint64_t ones = dup_const(esz, 1); ++ uint64_t signs = ones << (bits - 1); ++ uint64_t cmp0, cmp1; ++ ++ cmp1 = dup_const(esz, n); ++ cmp0 = cmp1 ^ m0; ++ cmp1 = cmp1 ^ m1; ++ cmp0 = (cmp0 - ones) & ~cmp0; ++ cmp1 = (cmp1 - ones) & ~cmp1; ++ return (cmp0 | cmp1) & signs; ++} ++ ++#define SETANYEQZ(NAME, MO) \ ++void HELPER(NAME)(CPULoongArchState *env, \ ++ uint32_t oprsz, uint32_t cd, uint32_t vj) \ ++{ \ ++ VReg *Vj = &(env->fpr[vj].vreg); \ ++ \ ++ env->cf[cd & 0x7] = do_match2(0, Vj->D(0), Vj->D(1), MO); \ ++ if (oprsz == 32) { \ ++ env->cf[cd & 0x7] = env->cf[cd & 0x7] || \ ++ do_match2(0, Vj->D(2), Vj->D(3), MO); \ ++ } \ ++} ++ ++SETANYEQZ(vsetanyeqz_b, MO_8) ++SETANYEQZ(vsetanyeqz_h, MO_16) ++SETANYEQZ(vsetanyeqz_w, MO_32) ++SETANYEQZ(vsetanyeqz_d, MO_64) ++ ++#define SETALLNEZ(NAME, MO) \ ++void HELPER(NAME)(CPULoongArchState *env, \ ++ uint32_t oprsz, uint32_t cd, uint32_t vj) \ ++{ \ ++ VReg *Vj = &(env->fpr[vj].vreg); \ ++ \ ++ env->cf[cd & 0x7]= !do_match2(0, Vj->D(0), Vj->D(1), MO); \ ++ if (oprsz == 32) { \ ++ env->cf[cd & 0x7] = env->cf[cd & 0x7] && \ ++ !do_match2(0, Vj->D(2), Vj->D(3), MO); \ ++ } \ ++} ++ ++SETALLNEZ(vsetallnez_b, MO_8) ++SETALLNEZ(vsetallnez_h, MO_16) ++SETALLNEZ(vsetallnez_w, MO_32) ++SETALLNEZ(vsetallnez_d, MO_64) ++ ++#define XVINSVE0(NAME, E, MASK) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ Vd->E(imm & MASK) = Vj->E(0); \ ++} ++ ++XVINSVE0(xvinsve0_w, W, 0x7) ++XVINSVE0(xvinsve0_d, D, 0x3) ++ ++#define XVPICKVE(NAME, E, BIT, MASK) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ Vd->E(0) = Vj->E(imm & MASK); \ ++ for (i = 1; i < oprsz / (BIT / 8); i++) { \ ++ Vd->E(i) = 0; \ ++ } \ ++} ++ ++XVPICKVE(xvpickve_w, W, 32, 0x7) ++XVPICKVE(xvpickve_d, D, 64, 0x3) ++ ++#define VPACKEV(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ temp.E(2 * i + 1) = Vj->E(2 * i); \ ++ temp.E(2 *i) = Vk->E(2 * i); \ ++ } \ ++ *Vd = temp; \ ++} ++ ++VPACKEV(vpackev_b, 16, B) ++VPACKEV(vpackev_h, 32, H) ++VPACKEV(vpackev_w, 64, W) ++VPACKEV(vpackev_d, 128, D) ++ ++#define VPACKOD(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ temp.E(2 * i + 1) = Vj->E(2 * i + 1); \ ++ temp.E(2 * i) = Vk->E(2 * i + 1); \ ++ } \ ++ *Vd = temp; \ ++} ++ ++VPACKOD(vpackod_b, 16, B) ++VPACKOD(vpackod_h, 32, H) ++VPACKOD(vpackod_w, 64, W) ++VPACKOD(vpackod_d, 128, D) ++ ++#define VPICKEV(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E(j + ofs * (2 * i + 1)) = Vj->E(2 * (j + ofs * i)); \ ++ temp.E(j + ofs * 2 * i) = Vk->E(2 * (j + ofs * i)); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++VPICKEV(vpickev_b, 16, B) ++VPICKEV(vpickev_h, 32, H) ++VPICKEV(vpickev_w, 64, W) ++VPICKEV(vpickev_d, 128, D) ++ ++#define VPICKOD(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E(j + ofs * (2 * i + 1)) = Vj->E(2 * (j + ofs * i) + 1); \ ++ temp.E(j + ofs * 2 * i) = Vk->E(2 * (j + ofs * i) + 1); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++VPICKOD(vpickod_b, 16, B) ++VPICKOD(vpickod_h, 32, H) ++VPICKOD(vpickod_w, 64, W) ++VPICKOD(vpickod_d, 128, D) ++ ++#define VILVL(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E(2 * (j + ofs * i) + 1) = Vj->E(j + ofs * 2 * i); \ ++ temp.E(2 * (j + ofs * i)) = Vk->E(j + ofs * 2 * i); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++VILVL(vilvl_b, 16, B) ++VILVL(vilvl_h, 32, H) ++VILVL(vilvl_w, 64, W) ++VILVL(vilvl_d, 128, D) ++ ++#define VILVH(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, ofs; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ ofs = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ for (j = 0; j < ofs; j++) { \ ++ temp.E(2 * (j + ofs * i) + 1) = Vj->E(j + ofs * (2 * i + 1)); \ ++ temp.E(2 * (j + ofs * i)) = Vk->E(j + ofs * (2 * i + 1)); \ ++ } \ ++ } \ ++ *Vd = temp; \ ++} ++ ++VILVH(vilvh_b, 16, B) ++VILVH(vilvh_h, 32, H) ++VILVH(vilvh_w, 64, W) ++VILVH(vilvh_d, 128, D) ++ ++void HELPER(vshuf_b)(void *vd, void *vj, void *vk, void *va, uint32_t desc) ++{ ++ int i, j, m; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ VReg *Va = (VReg *)va; ++ int oprsz = simd_oprsz(desc); ++ ++ m = LSX_LEN / 8; ++ for (i = 0; i < (oprsz / 16) * m; i++) { ++ j = i < m ? 0 : 1; ++ uint64_t k = (uint8_t)Va->B(i) % (2 * m); ++ temp.B(i) = k < m ? Vk->B(k + j * m): Vj->B(k + (j - 1) * m); ++ } ++ *Vd = temp; ++} ++ ++#define VSHUF(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ ++{ \ ++ int i, j, m; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ VReg *Vk = (VReg *)vk; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ m = LSX_LEN / BIT; \ ++ for (i = 0; i < (oprsz / 16) * m; i++) { \ ++ j = i < m ? 0 : 1; \ ++ uint64_t k = ((uint8_t)Vd->E(i)) % (2 * m); \ ++ temp.E(i) = k < m ? Vk->E(k + j * m) : Vj->E(k + (j - 1) * m); \ ++ } \ ++ *Vd = temp; \ ++} ++ ++VSHUF(vshuf_h, 16, H) ++VSHUF(vshuf_w, 32, W) ++VSHUF(vshuf_d, 64, D) ++ ++#define VSHUF4I(NAME, BIT, E) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, j, max; \ ++ VReg temp = {}; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ max = LSX_LEN / BIT; \ ++ for (i = 0; i < oprsz / (BIT / 8); i++) { \ ++ j = i < max ? 1 : 2; \ ++ temp.E(i) = Vj->E(SHF_POS(i - ((j -1)* max), imm) + (j - 1) * max); \ ++ } \ ++ *Vd = temp; \ ++} ++ ++VSHUF4I(vshuf4i_b, 8, B) ++VSHUF4I(vshuf4i_h, 16, H) ++VSHUF4I(vshuf4i_w, 32, W) ++ ++void HELPER(vshuf4i_d)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ temp.D(2 * i) = (imm & 2 ? Vj : Vd)->D((imm & 1) + 2 * i); ++ temp.D(2 * i + 1) = (imm & 8 ? Vj : Vd)->D(((imm >> 2) & 1) + 2 * i); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vperm_w)(void *vd, void *vj, void *vk, uint32_t desc) ++{ ++ int i, m; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ VReg *Vk = (VReg *)vk; ++ ++ m = LASX_LEN / 32; ++ for (i = 0; i < m ; i++) { ++ uint64_t k = (uint8_t)Vk->W(i) % 8; ++ temp.W(i) = Vj->W(k); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vpermi_w)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ int oprsz = simd_oprsz(desc); ++ ++ for (i = 0; i < oprsz / 16; i++) { ++ temp.W(4 * i) = Vj->W((imm & 0x3) + 4 * i); ++ temp.W(4 * i + 1) = Vj->W(((imm >> 2) & 0x3) + 4 * i); ++ temp.W(4 * i + 2) = Vd->W(((imm >> 4) & 0x3) + 4 * i); ++ temp.W(4 * i + 3) = Vd->W(((imm >> 6) & 0x3) + 4 * i); ++ } ++ *Vd = temp; ++} ++ ++void HELPER(vpermi_d)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ VReg temp = {}; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ ++ temp.D(0) = Vj->D(imm & 0x3); ++ temp.D(1) = Vj->D((imm >> 2) & 0x3); ++ temp.D(2) = Vj->D((imm >> 4) & 0x3); ++ temp.D(3) = Vj->D((imm >> 6) & 0x3); ++ *Vd = temp; ++} ++ ++void HELPER(vpermi_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) ++{ ++ int i; ++ VReg temp; ++ VReg *Vd = (VReg *)vd; ++ VReg *Vj = (VReg *)vj; ++ ++ for (i = 0; i < 2; i++, imm >>= 4) { ++ temp.Q(i) = (imm & 2 ? Vd: Vj)->Q(imm & 1); ++ } ++ *Vd = temp; ++} ++ ++#define VEXTRINS(NAME, BIT, E, MASK) \ ++void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ ++{ \ ++ int i, ins, extr, max; \ ++ VReg *Vd = (VReg *)vd; \ ++ VReg *Vj = (VReg *)vj; \ ++ int oprsz = simd_oprsz(desc); \ ++ \ ++ max = LSX_LEN / BIT; \ ++ ins = (imm >> 4) & MASK; \ ++ extr = imm & MASK; \ ++ for (i = 0; i < oprsz / 16; i++) { \ ++ Vd->E(ins + i * max) = Vj->E(extr + i * max); \ ++ } \ ++} ++ ++VEXTRINS(vextrins_b, 8, B, 0xf) ++VEXTRINS(vextrins_h, 16, H, 0x7) ++VEXTRINS(vextrins_w, 32, W, 0x3) ++VEXTRINS(vextrins_d, 64, D, 0x1) +diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c +deleted file mode 100644 +index 449043c..0000000 +--- a/target/loongarch/tlb_helper.c ++++ /dev/null +@@ -1,803 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * QEMU LoongArch TLB helpers +- * +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- * +- */ +- +-#include "qemu/osdep.h" +-#include "qemu/guest-random.h" +- +-#include "cpu.h" +-#include "internals.h" +-#include "exec/helper-proto.h" +-#include "exec/exec-all.h" +-#include "exec/cpu_ldst.h" +-#include "exec/log.h" +-#include "cpu-csr.h" +- +-enum { +- TLBRET_MATCH = 0, +- TLBRET_BADADDR = 1, +- TLBRET_NOMATCH = 2, +- TLBRET_INVALID = 3, +- TLBRET_DIRTY = 4, +- TLBRET_RI = 5, +- TLBRET_XI = 6, +- TLBRET_PE = 7, +-}; +- +-static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, +- int *prot, target_ulong address, +- int access_type, int index, int mmu_idx) +-{ +- LoongArchTLB *tlb = &env->tlb[index]; +- uint64_t plv = mmu_idx; +- uint64_t tlb_entry, tlb_ppn; +- uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv; +- +- if (index >= LOONGARCH_STLB) { +- tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); +- } else { +- tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); +- } +- n = (address >> tlb_ps) & 0x1;/* Odd or even */ +- +- tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0; +- tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V); +- tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D); +- tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV); +- if (is_la64(env)) { +- tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN); +- tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY_64, NX); +- tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY_64, NR); +- tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY_64, RPLV); +- } else { +- tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_32, PPN); +- tlb_nx = 0; +- tlb_nr = 0; +- tlb_rplv = 0; +- } +- +- /* Remove sw bit between bit12 -- bit PS*/ +- tlb_ppn = tlb_ppn & ~(((0x1UL << (tlb_ps - 12)) -1)); +- +- /* Check access rights */ +- if (!tlb_v) { +- return TLBRET_INVALID; +- } +- +- if (access_type == MMU_INST_FETCH && tlb_nx) { +- return TLBRET_XI; +- } +- +- if (access_type == MMU_DATA_LOAD && tlb_nr) { +- return TLBRET_RI; +- } +- +- if (((tlb_rplv == 0) && (plv > tlb_plv)) || +- ((tlb_rplv == 1) && (plv != tlb_plv))) { +- return TLBRET_PE; +- } +- +- if ((access_type == MMU_DATA_STORE) && !tlb_d) { +- return TLBRET_DIRTY; +- } +- +- *physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) | +- (address & MAKE_64BIT_MASK(0, tlb_ps)); +- *prot = PAGE_READ; +- if (tlb_d) { +- *prot |= PAGE_WRITE; +- } +- if (!tlb_nx) { +- *prot |= PAGE_EXEC; +- } +- return TLBRET_MATCH; +-} +- +-/* +- * One tlb entry holds an adjacent odd/even pair, the vpn is the +- * content of the virtual page number divided by 2. So the +- * compare vpn is bit[47:15] for 16KiB page. while the vppn +- * field in tlb entry contains bit[47:13], so need adjust. +- * virt_vpn = vaddr[47:13] +- */ +-static bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, +- int *index) +-{ +- LoongArchTLB *tlb; +- uint16_t csr_asid, tlb_asid, stlb_idx; +- uint8_t tlb_e, tlb_ps, tlb_g, stlb_ps; +- int i, compare_shift; +- uint64_t vpn, tlb_vppn; +- +- csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); +- stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); +- vpn = (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1); +- stlb_idx = vpn & 0xff; /* VA[25:15] <==> TLBIDX.index for 16KiB Page */ +- compare_shift = stlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; +- +- /* Search STLB */ +- for (i = 0; i < 8; ++i) { +- tlb = &env->tlb[i * 256 + stlb_idx]; +- tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); +- if (tlb_e) { +- tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); +- tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); +- tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); +- +- if ((tlb_g == 1 || tlb_asid == csr_asid) && +- (vpn == (tlb_vppn >> compare_shift))) { +- *index = i * 256 + stlb_idx; +- return true; +- } +- } +- } +- +- /* Search MTLB */ +- for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; ++i) { +- tlb = &env->tlb[i]; +- tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); +- if (tlb_e) { +- tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); +- tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); +- tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); +- tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); +- compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; +- vpn = (vaddr & TARGET_VIRT_MASK) >> (tlb_ps + 1); +- if ((tlb_g == 1 || tlb_asid == csr_asid) && +- (vpn == (tlb_vppn >> compare_shift))) { +- *index = i; +- return true; +- } +- } +- } +- return false; +-} +- +-static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, +- int *prot, target_ulong address, +- MMUAccessType access_type, int mmu_idx) +-{ +- int index, match; +- +- match = loongarch_tlb_search(env, address, &index); +- if (match) { +- return loongarch_map_tlb_entry(env, physical, prot, +- address, access_type, index, mmu_idx); +- } +- +- return TLBRET_NOMATCH; +-} +- +-static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va, +- target_ulong dmw) +-{ +- if (is_la64(env)) { +- return va & TARGET_VIRT_MASK; +- } else { +- uint32_t pseg = FIELD_EX32(dmw, CSR_DMW_32, PSEG); +- return (va & MAKE_64BIT_MASK(0, R_CSR_DMW_32_VSEG_SHIFT)) | \ +- (pseg << R_CSR_DMW_32_VSEG_SHIFT); +- } +-} +- +-static int get_physical_address(CPULoongArchState *env, hwaddr *physical, +- int *prot, target_ulong address, +- MMUAccessType access_type, int mmu_idx) +-{ +- int user_mode = mmu_idx == MMU_IDX_USER; +- int kernel_mode = mmu_idx == MMU_IDX_KERNEL; +- uint32_t plv, base_c, base_v; +- int64_t addr_high; +- uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA); +- uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG); +- +- /* Check PG and DA */ +- if (da & !pg) { +- *physical = address & TARGET_PHYS_MASK; +- *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; +- return TLBRET_MATCH; +- } +- +- plv = kernel_mode | (user_mode << R_CSR_DMW_PLV3_SHIFT); +- if (is_la64(env)) { +- base_v = address >> R_CSR_DMW_64_VSEG_SHIFT; +- } else { +- base_v = address >> R_CSR_DMW_32_VSEG_SHIFT; +- } +- /* Check direct map window */ +- for (int i = 0; i < 4; i++) { +- if (is_la64(env)) { +- base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW_64, VSEG); +- } else { +- base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW_32, VSEG); +- } +- if ((plv & env->CSR_DMW[i]) && (base_c == base_v)) { +- *physical = dmw_va2pa(env, address, env->CSR_DMW[i]); +- *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; +- return TLBRET_MATCH; +- } +- } +- +- /* Check valid extension */ +- addr_high = sextract64(address, TARGET_VIRT_ADDR_SPACE_BITS, 16); +- if (!(addr_high == 0 || addr_high == -1)) { +- return TLBRET_BADADDR; +- } +- +- /* Mapped address */ +- return loongarch_map_address(env, physical, prot, address, +- access_type, mmu_idx); +-} +- +-hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +-{ +- LoongArchCPU *cpu = LOONGARCH_CPU(cs); +- CPULoongArchState *env = &cpu->env; +- hwaddr phys_addr; +- int prot; +- +- if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD, +- cpu_mmu_index(env, false)) != 0) { +- return -1; +- } +- return phys_addr; +-} +- +-static void raise_mmu_exception(CPULoongArchState *env, target_ulong address, +- MMUAccessType access_type, int tlb_error) +-{ +- CPUState *cs = env_cpu(env); +- +- switch (tlb_error) { +- default: +- case TLBRET_BADADDR: +- cs->exception_index = access_type == MMU_INST_FETCH +- ? EXCCODE_ADEF : EXCCODE_ADEM; +- break; +- case TLBRET_NOMATCH: +- /* No TLB match for a mapped address */ +- if (access_type == MMU_DATA_LOAD) { +- cs->exception_index = EXCCODE_PIL; +- } else if (access_type == MMU_DATA_STORE) { +- cs->exception_index = EXCCODE_PIS; +- } else if (access_type == MMU_INST_FETCH) { +- cs->exception_index = EXCCODE_PIF; +- } +- env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 1); +- break; +- case TLBRET_INVALID: +- /* TLB match with no valid bit */ +- if (access_type == MMU_DATA_LOAD) { +- cs->exception_index = EXCCODE_PIL; +- } else if (access_type == MMU_DATA_STORE) { +- cs->exception_index = EXCCODE_PIS; +- } else if (access_type == MMU_INST_FETCH) { +- cs->exception_index = EXCCODE_PIF; +- } +- break; +- case TLBRET_DIRTY: +- /* TLB match but 'D' bit is cleared */ +- cs->exception_index = EXCCODE_PME; +- break; +- case TLBRET_XI: +- /* Execute-Inhibit Exception */ +- cs->exception_index = EXCCODE_PNX; +- break; +- case TLBRET_RI: +- /* Read-Inhibit Exception */ +- cs->exception_index = EXCCODE_PNR; +- break; +- case TLBRET_PE: +- /* Privileged Exception */ +- cs->exception_index = EXCCODE_PPI; +- break; +- } +- +- if (tlb_error == TLBRET_NOMATCH) { +- env->CSR_TLBRBADV = address; +- if (is_la64(env)) { +- env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI_64, +- VPPN, extract64(address, 13, 35)); +- } else { +- env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI_32, +- VPPN, extract64(address, 13, 19)); +- } +- } else { +- if (!FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) { +- env->CSR_BADV = address; +- } +- env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1); +- } +-} +- +-static void invalidate_tlb_entry(CPULoongArchState *env, int index) +-{ +- target_ulong addr, mask, pagesize; +- uint8_t tlb_ps; +- LoongArchTLB *tlb = &env->tlb[index]; +- +- int mmu_idx = cpu_mmu_index(env, false); +- uint8_t tlb_v0 = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, V); +- uint8_t tlb_v1 = FIELD_EX64(tlb->tlb_entry1, TLBENTRY, V); +- uint64_t tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); +- +- if (index >= LOONGARCH_STLB) { +- tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); +- } else { +- tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); +- } +- pagesize = MAKE_64BIT_MASK(tlb_ps, 1); +- mask = MAKE_64BIT_MASK(0, tlb_ps + 1); +- +- if (tlb_v0) { +- addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & ~mask; /* even */ +- tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize, +- mmu_idx, TARGET_LONG_BITS); +- } +- +- if (tlb_v1) { +- addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & pagesize; /* odd */ +- tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize, +- mmu_idx, TARGET_LONG_BITS); +- } +-} +- +-static void invalidate_tlb(CPULoongArchState *env, int index) +-{ +- LoongArchTLB *tlb; +- uint16_t csr_asid, tlb_asid, tlb_g; +- +- csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); +- tlb = &env->tlb[index]; +- tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); +- tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); +- if (tlb_g == 0 && tlb_asid != csr_asid) { +- return; +- } +- invalidate_tlb_entry(env, index); +-} +- +-static void fill_tlb_entry(CPULoongArchState *env, int index) +-{ +- LoongArchTLB *tlb = &env->tlb[index]; +- uint64_t lo0, lo1, csr_vppn; +- uint16_t csr_asid; +- uint8_t csr_ps; +- +- if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { +- csr_ps = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS); +- if (is_la64(env)) { +- csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI_64, VPPN); +- } else { +- csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI_32, VPPN); +- } +- lo0 = env->CSR_TLBRELO0; +- lo1 = env->CSR_TLBRELO1; +- } else { +- csr_ps = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS); +- if (is_la64(env)) { +- csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI_64, VPPN); +- } else { +- csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI_32, VPPN); +- } +- lo0 = env->CSR_TLBELO0; +- lo1 = env->CSR_TLBELO1; +- } +- +- if (csr_ps == 0) { +- qemu_log_mask(CPU_LOG_MMU, "page size is 0\n"); +- } +- +- /* Only MTLB has the ps fields */ +- if (index >= LOONGARCH_STLB) { +- tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, PS, csr_ps); +- } +- +- tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, VPPN, csr_vppn); +- tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 1); +- csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); +- tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, ASID, csr_asid); +- +- tlb->tlb_entry0 = lo0; +- tlb->tlb_entry1 = lo1; +-} +- +-/* Return an random value between low and high */ +-static uint32_t get_random_tlb(uint32_t low, uint32_t high) +-{ +- uint32_t val; +- +- qemu_guest_getrandom_nofail(&val, sizeof(val)); +- return val % (high - low + 1) + low; +-} +- +-void helper_tlbsrch(CPULoongArchState *env) +-{ +- int index, match; +- +- if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { +- match = loongarch_tlb_search(env, env->CSR_TLBREHI, &index); +- } else { +- match = loongarch_tlb_search(env, env->CSR_TLBEHI, &index); +- } +- +- if (match) { +- env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX, index); +- env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0); +- return; +- } +- +- env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1); +-} +- +-void helper_tlbrd(CPULoongArchState *env) +-{ +- LoongArchTLB *tlb; +- int index; +- uint8_t tlb_ps, tlb_e; +- +- index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); +- tlb = &env->tlb[index]; +- +- if (index >= LOONGARCH_STLB) { +- tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); +- } else { +- tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); +- } +- tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); +- +- if (!tlb_e) { +- /* Invalid TLB entry */ +- env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1); +- env->CSR_ASID = FIELD_DP64(env->CSR_ASID, CSR_ASID, ASID, 0); +- env->CSR_TLBEHI = 0; +- env->CSR_TLBELO0 = 0; +- env->CSR_TLBELO1 = 0; +- env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, PS, 0); +- } else { +- /* Valid TLB entry */ +- env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0); +- env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, +- PS, (tlb_ps & 0x3f)); +- env->CSR_TLBEHI = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN) << +- R_TLB_MISC_VPPN_SHIFT; +- env->CSR_TLBELO0 = tlb->tlb_entry0; +- env->CSR_TLBELO1 = tlb->tlb_entry1; +- } +-} +- +-void helper_tlbwr(CPULoongArchState *env) +-{ +- int index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); +- +- invalidate_tlb(env, index); +- +- if (FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, NE)) { +- env->tlb[index].tlb_misc = FIELD_DP64(env->tlb[index].tlb_misc, +- TLB_MISC, E, 0); +- return; +- } +- +- fill_tlb_entry(env, index); +-} +- +-void helper_tlbfill(CPULoongArchState *env) +-{ +- uint64_t address, entryhi; +- int index, set, stlb_idx; +- uint16_t pagesize, stlb_ps; +- +- if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { +- entryhi = env->CSR_TLBREHI; +- pagesize = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS); +- } else { +- entryhi = env->CSR_TLBEHI; +- pagesize = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS); +- } +- +- stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); +- +- if (pagesize == stlb_ps) { +- /* Only write into STLB bits [47:13] */ +- address = entryhi & ~MAKE_64BIT_MASK(0, R_CSR_TLBEHI_64_VPPN_SHIFT); +- +- /* Choose one set ramdomly */ +- set = get_random_tlb(0, 7); +- +- /* Index in one set */ +- stlb_idx = (address >> (stlb_ps + 1)) & 0xff; /* [0,255] */ +- +- index = set * 256 + stlb_idx; +- } else { +- /* Only write into MTLB */ +- index = get_random_tlb(LOONGARCH_STLB, LOONGARCH_TLB_MAX - 1); +- } +- +- invalidate_tlb(env, index); +- fill_tlb_entry(env, index); +-} +- +-void helper_tlbclr(CPULoongArchState *env) +-{ +- LoongArchTLB *tlb; +- int i, index; +- uint16_t csr_asid, tlb_asid, tlb_g; +- +- csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); +- index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); +- +- if (index < LOONGARCH_STLB) { +- /* STLB. One line per operation */ +- for (i = 0; i < 8; i++) { +- tlb = &env->tlb[i * 256 + (index % 256)]; +- tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); +- tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); +- if (!tlb_g && tlb_asid == csr_asid) { +- tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); +- } +- } +- } else if (index < LOONGARCH_TLB_MAX) { +- /* All MTLB entries */ +- for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { +- tlb = &env->tlb[i]; +- tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); +- tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); +- if (!tlb_g && tlb_asid == csr_asid) { +- tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); +- } +- } +- } +- +- tlb_flush(env_cpu(env)); +-} +- +-void helper_tlbflush(CPULoongArchState *env) +-{ +- int i, index; +- +- index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX); +- +- if (index < LOONGARCH_STLB) { +- /* STLB. One line per operation */ +- for (i = 0; i < 8; i++) { +- int s_idx = i * 256 + (index % 256); +- env->tlb[s_idx].tlb_misc = FIELD_DP64(env->tlb[s_idx].tlb_misc, +- TLB_MISC, E, 0); +- } +- } else if (index < LOONGARCH_TLB_MAX) { +- /* All MTLB entries */ +- for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { +- env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc, +- TLB_MISC, E, 0); +- } +- } +- +- tlb_flush(env_cpu(env)); +-} +- +-void helper_invtlb_all(CPULoongArchState *env) +-{ +- for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { +- env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc, +- TLB_MISC, E, 0); +- } +- tlb_flush(env_cpu(env)); +-} +- +-void helper_invtlb_all_g(CPULoongArchState *env, uint32_t g) +-{ +- for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { +- LoongArchTLB *tlb = &env->tlb[i]; +- uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); +- +- if (tlb_g == g) { +- tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); +- } +- } +- tlb_flush(env_cpu(env)); +-} +- +-void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info) +-{ +- uint16_t asid = info & R_CSR_ASID_ASID_MASK; +- +- for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { +- LoongArchTLB *tlb = &env->tlb[i]; +- uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); +- uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); +- +- if (!tlb_g && (tlb_asid == asid)) { +- tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); +- } +- } +- tlb_flush(env_cpu(env)); +-} +- +-void helper_invtlb_page_asid(CPULoongArchState *env, target_ulong info, +- target_ulong addr) +-{ +- uint16_t asid = info & 0x3ff; +- +- for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { +- LoongArchTLB *tlb = &env->tlb[i]; +- uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); +- uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); +- uint64_t vpn, tlb_vppn; +- uint8_t tlb_ps, compare_shift; +- +- if (i >= LOONGARCH_STLB) { +- tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); +- } else { +- tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); +- } +- tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); +- vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1); +- compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; +- +- if (!tlb_g && (tlb_asid == asid) && +- (vpn == (tlb_vppn >> compare_shift))) { +- tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); +- } +- } +- tlb_flush(env_cpu(env)); +-} +- +-void helper_invtlb_page_asid_or_g(CPULoongArchState *env, +- target_ulong info, target_ulong addr) +-{ +- uint16_t asid = info & 0x3ff; +- +- for (int i = 0; i < LOONGARCH_TLB_MAX; i++) { +- LoongArchTLB *tlb = &env->tlb[i]; +- uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); +- uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); +- uint64_t vpn, tlb_vppn; +- uint8_t tlb_ps, compare_shift; +- +- if (i >= LOONGARCH_STLB) { +- tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); +- } else { +- tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); +- } +- tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); +- vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1); +- compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; +- +- if ((tlb_g || (tlb_asid == asid)) && +- (vpn == (tlb_vppn >> compare_shift))) { +- tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); +- } +- } +- tlb_flush(env_cpu(env)); +-} +- +-bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, +- MMUAccessType access_type, int mmu_idx, +- bool probe, uintptr_t retaddr) +-{ +- LoongArchCPU *cpu = LOONGARCH_CPU(cs); +- CPULoongArchState *env = &cpu->env; +- hwaddr physical; +- int prot; +- int ret; +- +- /* Data access */ +- ret = get_physical_address(env, &physical, &prot, address, +- access_type, mmu_idx); +- +- if (ret == TLBRET_MATCH) { +- tlb_set_page(cs, address & TARGET_PAGE_MASK, +- physical & TARGET_PAGE_MASK, prot, +- mmu_idx, TARGET_PAGE_SIZE); +- qemu_log_mask(CPU_LOG_MMU, +- "%s address=%" VADDR_PRIx " physical " HWADDR_FMT_plx +- " prot %d\n", __func__, address, physical, prot); +- return true; +- } else { +- qemu_log_mask(CPU_LOG_MMU, +- "%s address=%" VADDR_PRIx " ret %d\n", __func__, address, +- ret); +- } +- if (probe) { +- return false; +- } +- raise_mmu_exception(env, address, access_type, ret); +- cpu_loop_exit_restore(cs, retaddr); +-} +- +-target_ulong helper_lddir(CPULoongArchState *env, target_ulong base, +- target_ulong level, uint32_t mem_idx) +-{ +- CPUState *cs = env_cpu(env); +- target_ulong badvaddr, index, phys, ret; +- int shift; +- uint64_t dir_base, dir_width; +- bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1; +- +- badvaddr = env->CSR_TLBRBADV; +- base = base & TARGET_PHYS_MASK; +- +- /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */ +- shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); +- shift = (shift + 1) * 3; +- +- if (huge) { +- return base; +- } +- switch (level) { +- case 1: +- dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE); +- dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH); +- break; +- case 2: +- dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE); +- dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH); +- break; +- case 3: +- dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE); +- dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH); +- break; +- case 4: +- dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE); +- dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH); +- break; +- default: +- do_raise_exception(env, EXCCODE_INE, GETPC()); +- return 0; +- } +- index = (badvaddr >> dir_base) & ((1 << dir_width) - 1); +- phys = base | index << shift; +- ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; +- return ret; +-} +- +-void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd, +- uint32_t mem_idx) +-{ +- CPUState *cs = env_cpu(env); +- target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv; +- int shift; +- bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1; +- uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); +- uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH); +- +- base = base & TARGET_PHYS_MASK; +- +- if (huge) { +- /* Huge Page. base is paddr */ +- tmp0 = base ^ (1 << LOONGARCH_PAGE_HUGE_SHIFT); +- /* Move Global bit */ +- tmp0 = ((tmp0 & (1 << LOONGARCH_HGLOBAL_SHIFT)) >> +- LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT | +- (tmp0 & (~(1 << LOONGARCH_HGLOBAL_SHIFT))); +- ps = ptbase + ptwidth - 1; +- if (odd) { +- tmp0 += MAKE_64BIT_MASK(ps, 1); +- } +- } else { +- /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */ +- shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); +- shift = (shift + 1) * 3; +- badv = env->CSR_TLBRBADV; +- +- ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1); +- ptindex = ptindex & ~0x1; /* clear bit 0 */ +- ptoffset0 = ptindex << shift; +- ptoffset1 = (ptindex + 1) << shift; +- +- phys = base | (odd ? ptoffset1 : ptoffset0); +- tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; +- ps = ptbase; +- } +- +- if (odd) { +- env->CSR_TLBRELO1 = tmp0; +- } else { +- env->CSR_TLBRELO0 = tmp0; +- } +- env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, PS, ps); +-} +diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c +deleted file mode 100644 +index 21f4db6..0000000 +--- a/target/loongarch/translate.c ++++ /dev/null +@@ -1,370 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * LoongArch emulation for QEMU - main translation routines. +- * +- * Copyright (c) 2021 Loongson Technology Corporation Limited +- */ +- +-#include "qemu/osdep.h" +-#include "cpu.h" +-#include "tcg/tcg-op.h" +-#include "tcg/tcg-op-gvec.h" +-#include "exec/translation-block.h" +-#include "exec/translator.h" +-#include "exec/helper-proto.h" +-#include "exec/helper-gen.h" +-#include "exec/log.h" +-#include "qemu/qemu-print.h" +-#include "fpu/softfloat.h" +-#include "translate.h" +-#include "internals.h" +-#include "vec.h" +- +-/* Global register indices */ +-TCGv cpu_gpr[32], cpu_pc; +-static TCGv cpu_lladdr, cpu_llval; +- +-#define HELPER_H "helper.h" +-#include "exec/helper-info.c.inc" +-#undef HELPER_H +- +-#define DISAS_STOP DISAS_TARGET_0 +-#define DISAS_EXIT DISAS_TARGET_1 +-#define DISAS_EXIT_UPDATE DISAS_TARGET_2 +- +-static inline int vec_full_offset(int regno) +-{ +- return offsetof(CPULoongArchState, fpr[regno]); +-} +- +-static inline int vec_reg_offset(int regno, int index, MemOp mop) +-{ +- const uint8_t size = 1 << mop; +- int offs = index * size; +- +- if (HOST_BIG_ENDIAN && size < 8 ) { +- offs ^= (8 - size); +- } +- +- return offs + vec_full_offset(regno); +-} +- +-static inline void get_vreg64(TCGv_i64 dest, int regno, int index) +-{ +- tcg_gen_ld_i64(dest, tcg_env, +- offsetof(CPULoongArchState, fpr[regno].vreg.D(index))); +-} +- +-static inline void set_vreg64(TCGv_i64 src, int regno, int index) +-{ +- tcg_gen_st_i64(src, tcg_env, +- offsetof(CPULoongArchState, fpr[regno].vreg.D(index))); +-} +- +-static inline int plus_1(DisasContext *ctx, int x) +-{ +- return x + 1; +-} +- +-static inline int shl_1(DisasContext *ctx, int x) +-{ +- return x << 1; +-} +- +-static inline int shl_2(DisasContext *ctx, int x) +-{ +- return x << 2; +-} +- +-static inline int shl_3(DisasContext *ctx, int x) +-{ +- return x << 3; +-} +- +-/* +- * LoongArch the upper 32 bits are undefined ("can be any value"). +- * QEMU chooses to nanbox, because it is most likely to show guest bugs early. +- */ +-static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in) +-{ +- tcg_gen_ori_i64(out, in, MAKE_64BIT_MASK(32, 32)); +-} +- +-void generate_exception(DisasContext *ctx, int excp) +-{ +- tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); +- gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp)); +- ctx->base.is_jmp = DISAS_NORETURN; +-} +- +-static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +-{ +- if (ctx->va32) { +- dest = (uint32_t) dest; +- } +- +- if (translator_use_goto_tb(&ctx->base, dest)) { +- tcg_gen_goto_tb(n); +- tcg_gen_movi_tl(cpu_pc, dest); +- tcg_gen_exit_tb(ctx->base.tb, n); +- } else { +- tcg_gen_movi_tl(cpu_pc, dest); +- tcg_gen_lookup_and_goto_ptr(); +- } +-} +- +-static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, +- CPUState *cs) +-{ +- int64_t bound; +- CPULoongArchState *env = cpu_env(cs); +- DisasContext *ctx = container_of(dcbase, DisasContext, base); +- +- ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; +- ctx->plv = ctx->base.tb->flags & HW_FLAGS_PLV_MASK; +- if (ctx->base.tb->flags & HW_FLAGS_CRMD_PG) { +- ctx->mem_idx = ctx->plv; +- } else { +- ctx->mem_idx = MMU_IDX_DA; +- } +- +- /* Bound the number of insns to execute to those left on the page. */ +- bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; +- ctx->base.max_insns = MIN(ctx->base.max_insns, bound); +- +- if (FIELD_EX64(env->cpucfg[2], CPUCFG2, LSX)) { +- ctx->vl = LSX_LEN; +- } +- +- if (FIELD_EX64(env->cpucfg[2], CPUCFG2, LASX)) { +- ctx->vl = LASX_LEN; +- } +- +- ctx->la64 = is_la64(env); +- ctx->va32 = (ctx->base.tb->flags & HW_FLAGS_VA32) != 0; +- +- ctx->zero = tcg_constant_tl(0); +- +- ctx->cpucfg1 = env->cpucfg[1]; +- ctx->cpucfg2 = env->cpucfg[2]; +-} +- +-static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) +-{ +-} +- +-static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) +-{ +- DisasContext *ctx = container_of(dcbase, DisasContext, base); +- +- tcg_gen_insn_start(ctx->base.pc_next); +-} +- +-/* +- * Wrappers for getting reg values. +- * +- * The $zero register does not have cpu_gpr[0] allocated -- we supply the +- * constant zero as a source, and an uninitialized sink as destination. +- * +- * Further, we may provide an extension for word operations. +- */ +-static TCGv gpr_src(DisasContext *ctx, int reg_num, DisasExtend src_ext) +-{ +- TCGv t; +- +- if (reg_num == 0) { +- return ctx->zero; +- } +- +- switch (src_ext) { +- case EXT_NONE: +- return cpu_gpr[reg_num]; +- case EXT_SIGN: +- t = tcg_temp_new(); +- tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]); +- return t; +- case EXT_ZERO: +- t = tcg_temp_new(); +- tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]); +- return t; +- } +- g_assert_not_reached(); +-} +- +-static TCGv gpr_dst(DisasContext *ctx, int reg_num, DisasExtend dst_ext) +-{ +- if (reg_num == 0 || dst_ext) { +- return tcg_temp_new(); +- } +- return cpu_gpr[reg_num]; +-} +- +-static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) +-{ +- if (reg_num != 0) { +- switch (dst_ext) { +- case EXT_NONE: +- tcg_gen_mov_tl(cpu_gpr[reg_num], t); +- break; +- case EXT_SIGN: +- tcg_gen_ext32s_tl(cpu_gpr[reg_num], t); +- break; +- case EXT_ZERO: +- tcg_gen_ext32u_tl(cpu_gpr[reg_num], t); +- break; +- default: +- g_assert_not_reached(); +- } +- } +-} +- +-static TCGv get_fpr(DisasContext *ctx, int reg_num) +-{ +- TCGv t = tcg_temp_new(); +- tcg_gen_ld_i64(t, tcg_env, +- offsetof(CPULoongArchState, fpr[reg_num].vreg.D(0))); +- return t; +-} +- +-static void set_fpr(int reg_num, TCGv val) +-{ +- tcg_gen_st_i64(val, tcg_env, +- offsetof(CPULoongArchState, fpr[reg_num].vreg.D(0))); +-} +- +-static TCGv make_address_x(DisasContext *ctx, TCGv base, TCGv addend) +-{ +- TCGv temp = NULL; +- +- if (addend || ctx->va32) { +- temp = tcg_temp_new(); +- } +- if (addend) { +- tcg_gen_add_tl(temp, base, addend); +- base = temp; +- } +- if (ctx->va32) { +- tcg_gen_ext32u_tl(temp, base); +- base = temp; +- } +- return base; +-} +- +-static TCGv make_address_i(DisasContext *ctx, TCGv base, target_long ofs) +-{ +- TCGv addend = ofs ? tcg_constant_tl(ofs) : NULL; +- return make_address_x(ctx, base, addend); +-} +- +-static uint64_t make_address_pc(DisasContext *ctx, uint64_t addr) +-{ +- if (ctx->va32) { +- addr = (int32_t)addr; +- } +- return addr; +-} +- +-#include "decode-insns.c.inc" +-#include "insn_trans/trans_arith.c.inc" +-#include "insn_trans/trans_shift.c.inc" +-#include "insn_trans/trans_bit.c.inc" +-#include "insn_trans/trans_memory.c.inc" +-#include "insn_trans/trans_atomic.c.inc" +-#include "insn_trans/trans_extra.c.inc" +-#include "insn_trans/trans_farith.c.inc" +-#include "insn_trans/trans_fcmp.c.inc" +-#include "insn_trans/trans_fcnv.c.inc" +-#include "insn_trans/trans_fmov.c.inc" +-#include "insn_trans/trans_fmemory.c.inc" +-#include "insn_trans/trans_branch.c.inc" +-#include "insn_trans/trans_privileged.c.inc" +-#include "insn_trans/trans_vec.c.inc" +- +-static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) +-{ +- CPULoongArchState *env = cpu_env(cs); +- DisasContext *ctx = container_of(dcbase, DisasContext, base); +- +- ctx->opcode = translator_ldl(env, &ctx->base, ctx->base.pc_next); +- +- if (!decode(ctx, ctx->opcode)) { +- qemu_log_mask(LOG_UNIMP, "Error: unknown opcode. " +- TARGET_FMT_lx ": 0x%x\n", +- ctx->base.pc_next, ctx->opcode); +- generate_exception(ctx, EXCCODE_INE); +- } +- +- ctx->base.pc_next += 4; +- +- if (ctx->va32) { +- ctx->base.pc_next = (uint32_t)ctx->base.pc_next; +- } +-} +- +-static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) +-{ +- DisasContext *ctx = container_of(dcbase, DisasContext, base); +- +- switch (ctx->base.is_jmp) { +- case DISAS_STOP: +- tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); +- tcg_gen_lookup_and_goto_ptr(); +- break; +- case DISAS_TOO_MANY: +- gen_goto_tb(ctx, 0, ctx->base.pc_next); +- break; +- case DISAS_NORETURN: +- break; +- case DISAS_EXIT_UPDATE: +- tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); +- QEMU_FALLTHROUGH; +- case DISAS_EXIT: +- tcg_gen_exit_tb(NULL, 0); +- break; +- default: +- g_assert_not_reached(); +- } +-} +- +-static void loongarch_tr_disas_log(const DisasContextBase *dcbase, +- CPUState *cpu, FILE *logfile) +-{ +- qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); +- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); +-} +- +-static const TranslatorOps loongarch_tr_ops = { +- .init_disas_context = loongarch_tr_init_disas_context, +- .tb_start = loongarch_tr_tb_start, +- .insn_start = loongarch_tr_insn_start, +- .translate_insn = loongarch_tr_translate_insn, +- .tb_stop = loongarch_tr_tb_stop, +- .disas_log = loongarch_tr_disas_log, +-}; +- +-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, +- target_ulong pc, void *host_pc) +-{ +- DisasContext ctx; +- +- translator_loop(cs, tb, max_insns, pc, host_pc, +- &loongarch_tr_ops, &ctx.base); +-} +- +-void loongarch_translate_init(void) +-{ +- int i; +- +- cpu_gpr[0] = NULL; +- for (i = 1; i < 32; i++) { +- cpu_gpr[i] = tcg_global_mem_new(tcg_env, +- offsetof(CPULoongArchState, gpr[i]), +- regnames[i]); +- } +- +- cpu_pc = tcg_global_mem_new(tcg_env, offsetof(CPULoongArchState, pc), "pc"); +- cpu_lladdr = tcg_global_mem_new(tcg_env, +- offsetof(CPULoongArchState, lladdr), "lladdr"); +- cpu_llval = tcg_global_mem_new(tcg_env, +- offsetof(CPULoongArchState, llval), "llval"); +-} +diff --git a/target/loongarch/vec_helper.c b/target/loongarch/vec_helper.c +deleted file mode 100644 +index 3faf52c..0000000 +--- a/target/loongarch/vec_helper.c ++++ /dev/null +@@ -1,3494 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * QEMU LoongArch vector helper functions. +- * +- * Copyright (c) 2022-2023 Loongson Technology Corporation Limited +- */ +- +-#include "qemu/osdep.h" +-#include "cpu.h" +-#include "exec/exec-all.h" +-#include "exec/helper-proto.h" +-#include "fpu/softfloat.h" +-#include "internals.h" +-#include "tcg/tcg.h" +-#include "vec.h" +-#include "tcg/tcg-gvec-desc.h" +- +-#define DO_ODD_EVEN(NAME, BIT, E1, E2, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- typedef __typeof(Vd->E1(0)) TD; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E1(i) = DO_OP((TD)Vj->E2(2 * i + 1), (TD)Vk->E2(2 * i)); \ +- } \ +-} +- +-DO_ODD_EVEN(vhaddw_h_b, 16, H, B, DO_ADD) +-DO_ODD_EVEN(vhaddw_w_h, 32, W, H, DO_ADD) +-DO_ODD_EVEN(vhaddw_d_w, 64, D, W, DO_ADD) +- +-void HELPER(vhaddw_q_d)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16 ; i++) { +- Vd->Q(i) = int128_add(int128_makes64(Vj->D(2 * i + 1)), +- int128_makes64(Vk->D(2 * i))); +- } +-} +- +-DO_ODD_EVEN(vhsubw_h_b, 16, H, B, DO_SUB) +-DO_ODD_EVEN(vhsubw_w_h, 32, W, H, DO_SUB) +-DO_ODD_EVEN(vhsubw_d_w, 64, D, W, DO_SUB) +- +-void HELPER(vhsubw_q_d)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_sub(int128_makes64(Vj->D(2 * i + 1)), +- int128_makes64(Vk->D(2 * i))); +- } +-} +- +-DO_ODD_EVEN(vhaddw_hu_bu, 16, UH, UB, DO_ADD) +-DO_ODD_EVEN(vhaddw_wu_hu, 32, UW, UH, DO_ADD) +-DO_ODD_EVEN(vhaddw_du_wu, 64, UD, UW, DO_ADD) +- +-void HELPER(vhaddw_qu_du)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i ++) { +- Vd->Q(i) = int128_add(int128_make64(Vj->UD(2 * i + 1)), +- int128_make64(Vk->UD(2 * i))); +- } +-} +- +-DO_ODD_EVEN(vhsubw_hu_bu, 16, UH, UB, DO_SUB) +-DO_ODD_EVEN(vhsubw_wu_hu, 32, UW, UH, DO_SUB) +-DO_ODD_EVEN(vhsubw_du_wu, 64, UD, UW, DO_SUB) +- +-void HELPER(vhsubw_qu_du)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_sub(int128_make64(Vj->UD(2 * i + 1)), +- int128_make64(Vk->UD(2 * i))); +- } +-} +- +-#define DO_EVEN(NAME, BIT, E1, E2, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- typedef __typeof(Vd->E1(0)) TD; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E1(i) = DO_OP((TD)Vj->E2(2 * i) ,(TD)Vk->E2(2 * i)); \ +- } \ +-} +- +-#define DO_ODD(NAME, BIT, E1, E2, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- typedef __typeof(Vd->E1(0)) TD; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E1(i) = DO_OP((TD)Vj->E2(2 * i + 1), (TD)Vk->E2(2 * i + 1)); \ +- } \ +-} +- +-void HELPER(vaddwev_q_d)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_add(int128_makes64(Vj->D(2 * i)), +- int128_makes64(Vk->D(2 * i))); +- } +-} +- +-DO_EVEN(vaddwev_h_b, 16, H, B, DO_ADD) +-DO_EVEN(vaddwev_w_h, 32, W, H, DO_ADD) +-DO_EVEN(vaddwev_d_w, 64, D, W, DO_ADD) +- +-void HELPER(vaddwod_q_d)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_add(int128_makes64(Vj->D(2 * i +1)), +- int128_makes64(Vk->D(2 * i +1))); +- } +-} +- +-DO_ODD(vaddwod_h_b, 16, H, B, DO_ADD) +-DO_ODD(vaddwod_w_h, 32, W, H, DO_ADD) +-DO_ODD(vaddwod_d_w, 64, D, W, DO_ADD) +- +-void HELPER(vsubwev_q_d)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_sub(int128_makes64(Vj->D(2 * i)), +- int128_makes64(Vk->D(2 * i))); +- } +-} +- +-DO_EVEN(vsubwev_h_b, 16, H, B, DO_SUB) +-DO_EVEN(vsubwev_w_h, 32, W, H, DO_SUB) +-DO_EVEN(vsubwev_d_w, 64, D, W, DO_SUB) +- +-void HELPER(vsubwod_q_d)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_sub(int128_makes64(Vj->D(2 * i + 1)), +- int128_makes64(Vk->D(2 * i + 1))); +- } +-} +- +-DO_ODD(vsubwod_h_b, 16, H, B, DO_SUB) +-DO_ODD(vsubwod_w_h, 32, W, H, DO_SUB) +-DO_ODD(vsubwod_d_w, 64, D, W, DO_SUB) +- +-void HELPER(vaddwev_q_du)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_add(int128_make64(Vj->UD(2 * i)), +- int128_make64(Vk->UD(2 * i))); +- } +-} +- +-DO_EVEN(vaddwev_h_bu, 16, UH, UB, DO_ADD) +-DO_EVEN(vaddwev_w_hu, 32, UW, UH, DO_ADD) +-DO_EVEN(vaddwev_d_wu, 64, UD, UW, DO_ADD) +- +-void HELPER(vaddwod_q_du)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_add(int128_make64(Vj->UD(2 * i + 1)), +- int128_make64(Vk->UD(2 * i + 1))); +- } +-} +- +-DO_ODD(vaddwod_h_bu, 16, UH, UB, DO_ADD) +-DO_ODD(vaddwod_w_hu, 32, UW, UH, DO_ADD) +-DO_ODD(vaddwod_d_wu, 64, UD, UW, DO_ADD) +- +-void HELPER(vsubwev_q_du)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_sub(int128_make64(Vj->UD(2 * i)), +- int128_make64(Vk->UD(2 * i))); +- } +-} +- +-DO_EVEN(vsubwev_h_bu, 16, UH, UB, DO_SUB) +-DO_EVEN(vsubwev_w_hu, 32, UW, UH, DO_SUB) +-DO_EVEN(vsubwev_d_wu, 64, UD, UW, DO_SUB) +- +-void HELPER(vsubwod_q_du)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_sub(int128_make64(Vj->UD(2 * i + 1)), +- int128_make64(Vk->UD(2 * i + 1))); +- } +-} +- +-DO_ODD(vsubwod_h_bu, 16, UH, UB, DO_SUB) +-DO_ODD(vsubwod_w_hu, 32, UW, UH, DO_SUB) +-DO_ODD(vsubwod_d_wu, 64, UD, UW, DO_SUB) +- +-#define DO_EVEN_U_S(NAME, BIT, ES1, EU1, ES2, EU2, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- typedef __typeof(Vd->ES1(0)) TDS; \ +- typedef __typeof(Vd->EU1(0)) TDU; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->ES1(i) = DO_OP((TDU)Vj->EU2(2 * i) ,(TDS)Vk->ES2(2 * i)); \ +- } \ +-} +- +-#define DO_ODD_U_S(NAME, BIT, ES1, EU1, ES2, EU2, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- typedef __typeof(Vd->ES1(0)) TDS; \ +- typedef __typeof(Vd->EU1(0)) TDU; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->ES1(i) = DO_OP((TDU)Vj->EU2(2 * i + 1), (TDS)Vk->ES2(2 * i + 1)); \ +- } \ +-} +- +-void HELPER(vaddwev_q_du_d)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_add(int128_make64(Vj->UD(2 * i)), +- int128_makes64(Vk->D(2 * i))); +- } +-} +- +-DO_EVEN_U_S(vaddwev_h_bu_b, 16, H, UH, B, UB, DO_ADD) +-DO_EVEN_U_S(vaddwev_w_hu_h, 32, W, UW, H, UH, DO_ADD) +-DO_EVEN_U_S(vaddwev_d_wu_w, 64, D, UD, W, UW, DO_ADD) +- +-void HELPER(vaddwod_q_du_d)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_add(int128_make64(Vj->UD(2 * i + 1)), +- int128_makes64(Vk->D(2 * i + 1))); +- } +-} +- +-DO_ODD_U_S(vaddwod_h_bu_b, 16, H, UH, B, UB, DO_ADD) +-DO_ODD_U_S(vaddwod_w_hu_h, 32, W, UW, H, UH, DO_ADD) +-DO_ODD_U_S(vaddwod_d_wu_w, 64, D, UD, W, UW, DO_ADD) +- +-#define DO_3OP(NAME, BIT, E, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = DO_OP(Vj->E(i), Vk->E(i)); \ +- } \ +-} +- +-DO_3OP(vavg_b, 8, B, DO_VAVG) +-DO_3OP(vavg_h, 16, H, DO_VAVG) +-DO_3OP(vavg_w, 32, W, DO_VAVG) +-DO_3OP(vavg_d, 64, D, DO_VAVG) +-DO_3OP(vavgr_b, 8, B, DO_VAVGR) +-DO_3OP(vavgr_h, 16, H, DO_VAVGR) +-DO_3OP(vavgr_w, 32, W, DO_VAVGR) +-DO_3OP(vavgr_d, 64, D, DO_VAVGR) +-DO_3OP(vavg_bu, 8, UB, DO_VAVG) +-DO_3OP(vavg_hu, 16, UH, DO_VAVG) +-DO_3OP(vavg_wu, 32, UW, DO_VAVG) +-DO_3OP(vavg_du, 64, UD, DO_VAVG) +-DO_3OP(vavgr_bu, 8, UB, DO_VAVGR) +-DO_3OP(vavgr_hu, 16, UH, DO_VAVGR) +-DO_3OP(vavgr_wu, 32, UW, DO_VAVGR) +-DO_3OP(vavgr_du, 64, UD, DO_VAVGR) +- +-DO_3OP(vabsd_b, 8, B, DO_VABSD) +-DO_3OP(vabsd_h, 16, H, DO_VABSD) +-DO_3OP(vabsd_w, 32, W, DO_VABSD) +-DO_3OP(vabsd_d, 64, D, DO_VABSD) +-DO_3OP(vabsd_bu, 8, UB, DO_VABSD) +-DO_3OP(vabsd_hu, 16, UH, DO_VABSD) +-DO_3OP(vabsd_wu, 32, UW, DO_VABSD) +-DO_3OP(vabsd_du, 64, UD, DO_VABSD) +- +-#define DO_VADDA(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = DO_VABS(Vj->E(i)) + DO_VABS(Vk->E(i)); \ +- } \ +-} +- +-DO_VADDA(vadda_b, 8, B) +-DO_VADDA(vadda_h, 16, H) +-DO_VADDA(vadda_w, 32, W) +-DO_VADDA(vadda_d, 64, D) +- +-#define VMINMAXI(NAME, BIT, E, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- typedef __typeof(Vd->E(0)) TD; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = DO_OP(Vj->E(i), (TD)imm); \ +- } \ +-} +- +-VMINMAXI(vmini_b, 8, B, DO_MIN) +-VMINMAXI(vmini_h, 16, H, DO_MIN) +-VMINMAXI(vmini_w, 32, W, DO_MIN) +-VMINMAXI(vmini_d, 64, D, DO_MIN) +-VMINMAXI(vmaxi_b, 8, B, DO_MAX) +-VMINMAXI(vmaxi_h, 16, H, DO_MAX) +-VMINMAXI(vmaxi_w, 32, W, DO_MAX) +-VMINMAXI(vmaxi_d, 64, D, DO_MAX) +-VMINMAXI(vmini_bu, 8, UB, DO_MIN) +-VMINMAXI(vmini_hu, 16, UH, DO_MIN) +-VMINMAXI(vmini_wu, 32, UW, DO_MIN) +-VMINMAXI(vmini_du, 64, UD, DO_MIN) +-VMINMAXI(vmaxi_bu, 8, UB, DO_MAX) +-VMINMAXI(vmaxi_hu, 16, UH, DO_MAX) +-VMINMAXI(vmaxi_wu, 32, UW, DO_MAX) +-VMINMAXI(vmaxi_du, 64, UD, DO_MAX) +- +-#define DO_VMUH(NAME, BIT, E1, E2, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- typedef __typeof(Vd->E1(0)) T; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E2(i) = ((T)Vj->E2(i)) * ((T)Vk->E2(i)) >> BIT; \ +- } \ +-} +- +-void HELPER(vmuh_d)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- uint64_t l, h; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 8; i++) { +- muls64(&l, &h, Vj->D(i), Vk->D(i)); +- Vd->D(i) = h; +- } +-} +- +-DO_VMUH(vmuh_b, 8, H, B, DO_MUH) +-DO_VMUH(vmuh_h, 16, W, H, DO_MUH) +-DO_VMUH(vmuh_w, 32, D, W, DO_MUH) +- +-void HELPER(vmuh_du)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i; +- uint64_t l, h; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 8; i++) { +- mulu64(&l, &h, Vj->D(i), Vk->D(i)); +- Vd->D(i) = h; +- } +-} +- +-DO_VMUH(vmuh_bu, 8, UH, UB, DO_MUH) +-DO_VMUH(vmuh_hu, 16, UW, UH, DO_MUH) +-DO_VMUH(vmuh_wu, 32, UD, UW, DO_MUH) +- +-DO_EVEN(vmulwev_h_b, 16, H, B, DO_MUL) +-DO_EVEN(vmulwev_w_h, 32, W, H, DO_MUL) +-DO_EVEN(vmulwev_d_w, 64, D, W, DO_MUL) +- +-DO_ODD(vmulwod_h_b, 16, H, B, DO_MUL) +-DO_ODD(vmulwod_w_h, 32, W, H, DO_MUL) +-DO_ODD(vmulwod_d_w, 64, D, W, DO_MUL) +- +-DO_EVEN(vmulwev_h_bu, 16, UH, UB, DO_MUL) +-DO_EVEN(vmulwev_w_hu, 32, UW, UH, DO_MUL) +-DO_EVEN(vmulwev_d_wu, 64, UD, UW, DO_MUL) +- +-DO_ODD(vmulwod_h_bu, 16, UH, UB, DO_MUL) +-DO_ODD(vmulwod_w_hu, 32, UW, UH, DO_MUL) +-DO_ODD(vmulwod_d_wu, 64, UD, UW, DO_MUL) +- +-DO_EVEN_U_S(vmulwev_h_bu_b, 16, H, UH, B, UB, DO_MUL) +-DO_EVEN_U_S(vmulwev_w_hu_h, 32, W, UW, H, UH, DO_MUL) +-DO_EVEN_U_S(vmulwev_d_wu_w, 64, D, UD, W, UW, DO_MUL) +- +-DO_ODD_U_S(vmulwod_h_bu_b, 16, H, UH, B, UB, DO_MUL) +-DO_ODD_U_S(vmulwod_w_hu_h, 32, W, UW, H, UH, DO_MUL) +-DO_ODD_U_S(vmulwod_d_wu_w, 64, D, UD, W, UW, DO_MUL) +- +-#define VMADDSUB(NAME, BIT, E, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = DO_OP(Vd->E(i), Vj->E(i) ,Vk->E(i)); \ +- } \ +-} +- +-VMADDSUB(vmadd_b, 8, B, DO_MADD) +-VMADDSUB(vmadd_h, 16, H, DO_MADD) +-VMADDSUB(vmadd_w, 32, W, DO_MADD) +-VMADDSUB(vmadd_d, 64, D, DO_MADD) +-VMADDSUB(vmsub_b, 8, B, DO_MSUB) +-VMADDSUB(vmsub_h, 16, H, DO_MSUB) +-VMADDSUB(vmsub_w, 32, W, DO_MSUB) +-VMADDSUB(vmsub_d, 64, D, DO_MSUB) +- +-#define VMADDWEV(NAME, BIT, E1, E2, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- typedef __typeof(Vd->E1(0)) TD; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E1(i) += DO_OP((TD)Vj->E2(2 * i), (TD)Vk->E2(2 * i)); \ +- } \ +-} +- +-VMADDWEV(vmaddwev_h_b, 16, H, B, DO_MUL) +-VMADDWEV(vmaddwev_w_h, 32, W, H, DO_MUL) +-VMADDWEV(vmaddwev_d_w, 64, D, W, DO_MUL) +-VMADDWEV(vmaddwev_h_bu, 16, UH, UB, DO_MUL) +-VMADDWEV(vmaddwev_w_hu, 32, UW, UH, DO_MUL) +-VMADDWEV(vmaddwev_d_wu, 64, UD, UW, DO_MUL) +- +-#define VMADDWOD(NAME, BIT, E1, E2, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- typedef __typeof(Vd->E1(0)) TD; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E1(i) += DO_OP((TD)Vj->E2(2 * i + 1), \ +- (TD)Vk->E2(2 * i + 1)); \ +- } \ +-} +- +-VMADDWOD(vmaddwod_h_b, 16, H, B, DO_MUL) +-VMADDWOD(vmaddwod_w_h, 32, W, H, DO_MUL) +-VMADDWOD(vmaddwod_d_w, 64, D, W, DO_MUL) +-VMADDWOD(vmaddwod_h_bu, 16, UH, UB, DO_MUL) +-VMADDWOD(vmaddwod_w_hu, 32, UW, UH, DO_MUL) +-VMADDWOD(vmaddwod_d_wu, 64, UD, UW, DO_MUL) +- +-#define VMADDWEV_U_S(NAME, BIT, ES1, EU1, ES2, EU2, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- typedef __typeof(Vd->ES1(0)) TS1; \ +- typedef __typeof(Vd->EU1(0)) TU1; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->ES1(i) += DO_OP((TU1)Vj->EU2(2 * i), \ +- (TS1)Vk->ES2(2 * i)); \ +- } \ +-} +- +-VMADDWEV_U_S(vmaddwev_h_bu_b, 16, H, UH, B, UB, DO_MUL) +-VMADDWEV_U_S(vmaddwev_w_hu_h, 32, W, UW, H, UH, DO_MUL) +-VMADDWEV_U_S(vmaddwev_d_wu_w, 64, D, UD, W, UW, DO_MUL) +- +-#define VMADDWOD_U_S(NAME, BIT, ES1, EU1, ES2, EU2, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- typedef __typeof(Vd->ES1(0)) TS1; \ +- typedef __typeof(Vd->EU1(0)) TU1; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->ES1(i) += DO_OP((TU1)Vj->EU2(2 * i + 1), \ +- (TS1)Vk->ES2(2 * i + 1)); \ +- } \ +-} +- +-VMADDWOD_U_S(vmaddwod_h_bu_b, 16, H, UH, B, UB, DO_MUL) +-VMADDWOD_U_S(vmaddwod_w_hu_h, 32, W, UW, H, UH, DO_MUL) +-VMADDWOD_U_S(vmaddwod_d_wu_w, 64, D, UD, W, UW, DO_MUL) +- +-#define VDIV(NAME, BIT, E, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = DO_OP(Vj->E(i), Vk->E(i)); \ +- } \ +-} +- +-VDIV(vdiv_b, 8, B, DO_DIV) +-VDIV(vdiv_h, 16, H, DO_DIV) +-VDIV(vdiv_w, 32, W, DO_DIV) +-VDIV(vdiv_d, 64, D, DO_DIV) +-VDIV(vdiv_bu, 8, UB, DO_DIVU) +-VDIV(vdiv_hu, 16, UH, DO_DIVU) +-VDIV(vdiv_wu, 32, UW, DO_DIVU) +-VDIV(vdiv_du, 64, UD, DO_DIVU) +-VDIV(vmod_b, 8, B, DO_REM) +-VDIV(vmod_h, 16, H, DO_REM) +-VDIV(vmod_w, 32, W, DO_REM) +-VDIV(vmod_d, 64, D, DO_REM) +-VDIV(vmod_bu, 8, UB, DO_REMU) +-VDIV(vmod_hu, 16, UH, DO_REMU) +-VDIV(vmod_wu, 32, UW, DO_REMU) +-VDIV(vmod_du, 64, UD, DO_REMU) +- +-#define VSAT_S(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t max, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- typedef __typeof(Vd->E(0)) TD; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = Vj->E(i) > (TD)max ? (TD)max : \ +- Vj->E(i) < (TD)~max ? (TD)~max: Vj->E(i); \ +- } \ +-} +- +-VSAT_S(vsat_b, 8, B) +-VSAT_S(vsat_h, 16, H) +-VSAT_S(vsat_w, 32, W) +-VSAT_S(vsat_d, 64, D) +- +-#define VSAT_U(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t max, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- typedef __typeof(Vd->E(0)) TD; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = Vj->E(i) > (TD)max ? (TD)max : Vj->E(i); \ +- } \ +-} +- +-VSAT_U(vsat_bu, 8, UB) +-VSAT_U(vsat_hu, 16, UH) +-VSAT_U(vsat_wu, 32, UW) +-VSAT_U(vsat_du, 64, UD) +- +-#define VEXTH(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + i * ofs) = Vj->E2(j + ofs + ofs * 2 * i); \ +- } \ +- } \ +-} +- +-void HELPER(vexth_q_d)(void *vd, void *vj, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_makes64(Vj->D(2 * i + 1)); +- } +-} +- +-void HELPER(vexth_qu_du)(void *vd, void *vj, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_make64(Vj->UD(2 * i + 1)); +- } +-} +- +-VEXTH(vexth_h_b, 16, H, B) +-VEXTH(vexth_w_h, 32, W, H) +-VEXTH(vexth_d_w, 64, D, W) +-VEXTH(vexth_hu_bu, 16, UH, UB) +-VEXTH(vexth_wu_hu, 32, UW, UH) +-VEXTH(vexth_du_wu, 64, UD, UW) +- +-#define VEXT2XV(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint32_t desc) \ +-{ \ +- int i; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- temp.E1(i) = Vj->E2(i); \ +- } \ +- *Vd = temp; \ +-} +- +-VEXT2XV(vext2xv_h_b, 16, H, B) +-VEXT2XV(vext2xv_w_b, 32, W, B) +-VEXT2XV(vext2xv_d_b, 64, D, B) +-VEXT2XV(vext2xv_w_h, 32, W, H) +-VEXT2XV(vext2xv_d_h, 64, D, H) +-VEXT2XV(vext2xv_d_w, 64, D, W) +-VEXT2XV(vext2xv_hu_bu, 16, UH, UB) +-VEXT2XV(vext2xv_wu_bu, 32, UW, UB) +-VEXT2XV(vext2xv_du_bu, 64, UD, UB) +-VEXT2XV(vext2xv_wu_hu, 32, UW, UH) +-VEXT2XV(vext2xv_du_hu, 64, UD, UH) +-VEXT2XV(vext2xv_du_wu, 64, UD, UW) +- +-DO_3OP(vsigncov_b, 8, B, DO_SIGNCOV) +-DO_3OP(vsigncov_h, 16, H, DO_SIGNCOV) +-DO_3OP(vsigncov_w, 32, W, DO_SIGNCOV) +-DO_3OP(vsigncov_d, 64, D, DO_SIGNCOV) +- +-static uint64_t do_vmskltz_b(int64_t val) +-{ +- uint64_t m = 0x8080808080808080ULL; +- uint64_t c = val & m; +- c |= c << 7; +- c |= c << 14; +- c |= c << 28; +- return c >> 56; +-} +- +-void HELPER(vmskltz_b)(void *vd, void *vj, uint32_t desc) +-{ +- int i; +- uint16_t temp = 0; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- temp = 0; +- temp = do_vmskltz_b(Vj->D(2 * i)); +- temp |= (do_vmskltz_b(Vj->D(2 * i + 1)) << 8); +- Vd->D(2 * i) = temp; +- Vd->D(2 * i + 1) = 0; +- } +-} +- +-static uint64_t do_vmskltz_h(int64_t val) +-{ +- uint64_t m = 0x8000800080008000ULL; +- uint64_t c = val & m; +- c |= c << 15; +- c |= c << 30; +- return c >> 60; +-} +- +-void HELPER(vmskltz_h)(void *vd, void *vj, uint32_t desc) +-{ +- int i; +- uint16_t temp = 0; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- temp = 0; +- temp = do_vmskltz_h(Vj->D(2 * i)); +- temp |= (do_vmskltz_h(Vj->D(2 * i + 1)) << 4); +- Vd->D(2 * i) = temp; +- Vd->D(2 * i + 1) = 0; +- } +-} +- +-static uint64_t do_vmskltz_w(int64_t val) +-{ +- uint64_t m = 0x8000000080000000ULL; +- uint64_t c = val & m; +- c |= c << 31; +- return c >> 62; +-} +- +-void HELPER(vmskltz_w)(void *vd, void *vj, uint32_t desc) +-{ +- int i; +- uint16_t temp = 0; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- temp = 0; +- temp = do_vmskltz_w(Vj->D(2 * i)); +- temp |= (do_vmskltz_w(Vj->D(2 * i + 1)) << 2); +- Vd->D(2 * i) = temp; +- Vd->D(2 * i + 1) = 0; +- } +-} +- +-static uint64_t do_vmskltz_d(int64_t val) +-{ +- return (uint64_t)val >> 63; +-} +-void HELPER(vmskltz_d)(void *vd, void *vj, uint32_t desc) +-{ +- int i; +- uint16_t temp = 0; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- temp = 0; +- temp = do_vmskltz_d(Vj->D(2 * i)); +- temp |= (do_vmskltz_d(Vj->D(2 * i + 1)) << 1); +- Vd->D(2 * i) = temp; +- Vd->D(2 * i + 1) = 0; +- } +-} +- +-void HELPER(vmskgez_b)(void *vd, void *vj, uint32_t desc) +-{ +- int i; +- uint16_t temp = 0; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- temp = 0; +- temp = do_vmskltz_b(Vj->D(2 * i)); +- temp |= (do_vmskltz_b(Vj->D(2 * i + 1)) << 8); +- Vd->D(2 * i) = (uint16_t)(~temp); +- Vd->D(2 * i + 1) = 0; +- } +-} +- +-static uint64_t do_vmskez_b(uint64_t a) +-{ +- uint64_t m = 0x7f7f7f7f7f7f7f7fULL; +- uint64_t c = ~(((a & m) + m) | a | m); +- c |= c << 7; +- c |= c << 14; +- c |= c << 28; +- return c >> 56; +-} +- +-void HELPER(vmsknz_b)(void *vd, void *vj, uint32_t desc) +-{ +- int i; +- uint16_t temp = 0; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- temp = 0; +- temp = do_vmskez_b(Vj->D(2 * i)); +- temp |= (do_vmskez_b(Vj->D(2 * i + 1)) << 8); +- Vd->D(2 * i) = (uint16_t)(~temp); +- Vd->D(2 * i + 1) = 0; +- } +-} +- +-void HELPER(vnori_b)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- +- for (i = 0; i < simd_oprsz(desc); i++) { +- Vd->B(i) = ~(Vj->B(i) | (uint8_t)imm); +- } +-} +- +-#define VSLLWIL(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- typedef __typeof(temp.E1(0)) TD; \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * i) = (TD)Vj->E2(j + ofs * 2 * i) << (imm % BIT); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +- +-void HELPER(vextl_q_d)(void *vd, void *vj, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_makes64(Vj->D(2 * i)); +- } +-} +- +-void HELPER(vextl_qu_du)(void *vd, void *vj, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- Vd->Q(i) = int128_make64(Vj->UD(2 * i)); +- } +-} +- +-VSLLWIL(vsllwil_h_b, 16, H, B) +-VSLLWIL(vsllwil_w_h, 32, W, H) +-VSLLWIL(vsllwil_d_w, 64, D, W) +-VSLLWIL(vsllwil_hu_bu, 16, UH, UB) +-VSLLWIL(vsllwil_wu_hu, 32, UW, UH) +-VSLLWIL(vsllwil_du_wu, 64, UD, UW) +- +-#define do_vsrlr(E, T) \ +-static T do_vsrlr_ ##E(T s1, int sh) \ +-{ \ +- if (sh == 0) { \ +- return s1; \ +- } else { \ +- return (s1 >> sh) + ((s1 >> (sh - 1)) & 0x1); \ +- } \ +-} +- +-do_vsrlr(B, uint8_t) +-do_vsrlr(H, uint16_t) +-do_vsrlr(W, uint32_t) +-do_vsrlr(D, uint64_t) +- +-#define VSRLR(NAME, BIT, T, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = do_vsrlr_ ## E(Vj->E(i), ((T)Vk->E(i))%BIT); \ +- } \ +-} +- +-VSRLR(vsrlr_b, 8, uint8_t, B) +-VSRLR(vsrlr_h, 16, uint16_t, H) +-VSRLR(vsrlr_w, 32, uint32_t, W) +-VSRLR(vsrlr_d, 64, uint64_t, D) +- +-#define VSRLRI(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = do_vsrlr_ ## E(Vj->E(i), imm); \ +- } \ +-} +- +-VSRLRI(vsrlri_b, 8, B) +-VSRLRI(vsrlri_h, 16, H) +-VSRLRI(vsrlri_w, 32, W) +-VSRLRI(vsrlri_d, 64, D) +- +-#define do_vsrar(E, T) \ +-static T do_vsrar_ ##E(T s1, int sh) \ +-{ \ +- if (sh == 0) { \ +- return s1; \ +- } else { \ +- return (s1 >> sh) + ((s1 >> (sh - 1)) & 0x1); \ +- } \ +-} +- +-do_vsrar(B, int8_t) +-do_vsrar(H, int16_t) +-do_vsrar(W, int32_t) +-do_vsrar(D, int64_t) +- +-#define VSRAR(NAME, BIT, T, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = do_vsrar_ ## E(Vj->E(i), ((T)Vk->E(i))%BIT); \ +- } \ +-} +- +-VSRAR(vsrar_b, 8, uint8_t, B) +-VSRAR(vsrar_h, 16, uint16_t, H) +-VSRAR(vsrar_w, 32, uint32_t, W) +-VSRAR(vsrar_d, 64, uint64_t, D) +- +-#define VSRARI(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = do_vsrar_ ## E(Vj->E(i), imm); \ +- } \ +-} +- +-VSRARI(vsrari_b, 8, B) +-VSRARI(vsrari_h, 16, H) +-VSRARI(vsrari_w, 32, W) +-VSRARI(vsrari_d, 64, D) +- +-#define VSRLN(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = R_SHIFT(Vj->E2(j + ofs * i), \ +- Vk->E2(j + ofs * i) % BIT); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSRLN(vsrln_b_h, 16, B, UH) +-VSRLN(vsrln_h_w, 32, H, UW) +-VSRLN(vsrln_w_d, 64, W, UD) +- +-#define VSRAN(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = R_SHIFT(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSRAN(vsran_b_h, 16, B, H, UH) +-VSRAN(vsran_h_w, 32, H, W, UW) +-VSRAN(vsran_w_d, 64, W, D, UD) +- +-#define VSRLNI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = R_SHIFT(Vj->E2(j + ofs * i), imm); \ +- temp.E1(j + ofs * (2 * i + 1)) = R_SHIFT(Vd->E2(j + ofs * i), \ +- imm); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-void HELPER(vsrlni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- +- for (i = 0; i < 2; i++) { +- temp.D(2 * i) = int128_getlo(int128_urshift(Vj->Q(i), imm % 128)); +- temp.D(2 * i +1) = int128_getlo(int128_urshift(Vd->Q(i), imm % 128)); +- } +- *Vd = temp; +-} +- +-VSRLNI(vsrlni_b_h, 16, B, UH) +-VSRLNI(vsrlni_h_w, 32, H, UW) +-VSRLNI(vsrlni_w_d, 64, W, UD) +- +-#define VSRANI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = R_SHIFT(Vj->E2(j + ofs * i), imm); \ +- temp.E1(j + ofs * (2 * i + 1)) = R_SHIFT(Vd->E2(j + ofs * i), \ +- imm); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-void HELPER(vsrani_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- +- for (i = 0; i < 2; i++) { +- temp.D(2 * i) = int128_getlo(int128_rshift(Vj->Q(i), imm % 128)); +- temp.D(2 * i + 1) = int128_getlo(int128_rshift(Vd->Q(i), imm % 128)); +- } +- *Vd = temp; +-} +- +-VSRANI(vsrani_b_h, 16, B, H) +-VSRANI(vsrani_h_w, 32, H, W) +-VSRANI(vsrani_w_d, 64, W, D) +- +-#define VSRLRN(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = do_vsrlr_ ##E2(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSRLRN(vsrlrn_b_h, 16, B, H, UH) +-VSRLRN(vsrlrn_h_w, 32, H, W, UW) +-VSRLRN(vsrlrn_w_d, 64, W, D, UD) +- +-#define VSRARN(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = do_vsrar_ ## E2(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSRARN(vsrarn_b_h, 16, B, H, UH) +-VSRARN(vsrarn_h_w, 32, H, W, UW) +-VSRARN(vsrarn_w_d, 64, W, D, UD) +- +-#define VSRLRNI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = do_vsrlr_ ## E2(Vj->E2(j + ofs * i), imm); \ +- temp.E1(j + ofs * (2 * i + 1)) = do_vsrlr_ ## E2(Vd->E2(j + ofs * i), \ +- imm); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-void HELPER(vsrlrni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- Int128 r[4]; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- if (imm == 0) { +- temp.D(2 * i) = int128_getlo(Vj->Q(i)); +- temp.D(2 * i + 1) = int128_getlo(Vd->Q(i)); +- } else { +- r[2 * i] = int128_and(int128_urshift(Vj->Q(i), (imm - 1)), +- int128_one()); +- r[2 * i + 1] = int128_and(int128_urshift(Vd->Q(i), (imm - 1)), +- int128_one()); +- temp.D(2 * i) = int128_getlo(int128_add(int128_urshift(Vj->Q(i), +- imm), r[2 * i])); +- temp.D(2 * i + 1) = int128_getlo(int128_add(int128_urshift(Vd->Q(i), +- imm), r[ 2 * i + 1])); +- } +- } +- *Vd = temp; +-} +- +-VSRLRNI(vsrlrni_b_h, 16, B, H) +-VSRLRNI(vsrlrni_h_w, 32, H, W) +-VSRLRNI(vsrlrni_w_d, 64, W, D) +- +-#define VSRARNI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = do_vsrar_ ## E2(Vj->E2(j + ofs * i), imm); \ +- temp.E1(j + ofs * (2 * i + 1)) = do_vsrar_ ## E2(Vd->E2(j + ofs * i), \ +- imm); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-void HELPER(vsrarni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- Int128 r[4]; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- if (imm == 0) { +- temp.D(2 * i) = int128_getlo(Vj->Q(i)); +- temp.D(2 * i + 1) = int128_getlo(Vd->Q(i)); +- } else { +- r[2 * i] = int128_and(int128_rshift(Vj->Q(i), (imm - 1)), +- int128_one()); +- r[2 * i + 1] = int128_and(int128_rshift(Vd->Q(i), (imm - 1)), +- int128_one()); +- temp.D(2 * i) = int128_getlo(int128_add(int128_rshift(Vj->Q(i), +- imm), r[2 * i])); +- temp.D(2 * i + 1) = int128_getlo(int128_add(int128_rshift(Vd->Q(i), +- imm), r[2 * i + 1])); +- } +- } +- *Vd = temp; +-} +- +-VSRARNI(vsrarni_b_h, 16, B, H) +-VSRARNI(vsrarni_h_w, 32, H, W) +-VSRARNI(vsrarni_w_d, 64, W, D) +- +-#define SSRLNS(NAME, T1, T2, T3) \ +-static T1 do_ssrlns_ ## NAME(T2 e2, int sa, int sh) \ +-{ \ +- T1 shft_res; \ +- if (sa == 0) { \ +- shft_res = e2; \ +- } else { \ +- shft_res = (((T1)e2) >> sa); \ +- } \ +- T3 mask; \ +- mask = (1ull << sh) -1; \ +- if (shft_res > mask) { \ +- return mask; \ +- } else { \ +- return shft_res; \ +- } \ +-} +- +-SSRLNS(B, uint16_t, int16_t, uint8_t) +-SSRLNS(H, uint32_t, int32_t, uint16_t) +-SSRLNS(W, uint64_t, int64_t, uint32_t) +- +-#define VSSRLN(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = do_ssrlns_ ## E1(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT, \ +- BIT / 2 - 1); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSSRLN(vssrln_b_h, 16, B, H, UH) +-VSSRLN(vssrln_h_w, 32, H, W, UW) +-VSSRLN(vssrln_w_d, 64, W, D, UD) +- +-#define SSRANS(E, T1, T2) \ +-static T1 do_ssrans_ ## E(T1 e2, int sa, int sh) \ +-{ \ +- T1 shft_res; \ +- if (sa == 0) { \ +- shft_res = e2; \ +- } else { \ +- shft_res = e2 >> sa; \ +- } \ +- T2 mask; \ +- mask = (1ll << sh) - 1; \ +- if (shft_res > mask) { \ +- return mask; \ +- } else if (shft_res < -(mask + 1)) { \ +- return ~mask; \ +- } else { \ +- return shft_res; \ +- } \ +-} +- +-SSRANS(B, int16_t, int8_t) +-SSRANS(H, int32_t, int16_t) +-SSRANS(W, int64_t, int32_t) +- +-#define VSSRAN(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = do_ssrans_ ## E1(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT, \ +- BIT / 2 - 1); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSSRAN(vssran_b_h, 16, B, H, UH) +-VSSRAN(vssran_h_w, 32, H, W, UW) +-VSSRAN(vssran_w_d, 64, W, D, UD) +- +-#define SSRLNU(E, T1, T2, T3) \ +-static T1 do_ssrlnu_ ## E(T3 e2, int sa, int sh) \ +-{ \ +- T1 shft_res; \ +- if (sa == 0) { \ +- shft_res = e2; \ +- } else { \ +- shft_res = (((T1)e2) >> sa); \ +- } \ +- T2 mask; \ +- mask = (1ull << sh) - 1; \ +- if (shft_res > mask) { \ +- return mask; \ +- } else { \ +- return shft_res; \ +- } \ +-} +- +-SSRLNU(B, uint16_t, uint8_t, int16_t) +-SSRLNU(H, uint32_t, uint16_t, int32_t) +-SSRLNU(W, uint64_t, uint32_t, int64_t) +- +-#define VSSRLNU(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = do_ssrlnu_ ## E1(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT, \ +- BIT / 2); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSSRLNU(vssrln_bu_h, 16, B, H, UH) +-VSSRLNU(vssrln_hu_w, 32, H, W, UW) +-VSSRLNU(vssrln_wu_d, 64, W, D, UD) +- +-#define SSRANU(E, T1, T2, T3) \ +-static T1 do_ssranu_ ## E(T3 e2, int sa, int sh) \ +-{ \ +- T1 shft_res; \ +- if (sa == 0) { \ +- shft_res = e2; \ +- } else { \ +- shft_res = e2 >> sa; \ +- } \ +- if (e2 < 0) { \ +- shft_res = 0; \ +- } \ +- T2 mask; \ +- mask = (1ull << sh) - 1; \ +- if (shft_res > mask) { \ +- return mask; \ +- } else { \ +- return shft_res; \ +- } \ +-} +- +-SSRANU(B, uint16_t, uint8_t, int16_t) +-SSRANU(H, uint32_t, uint16_t, int32_t) +-SSRANU(W, uint64_t, uint32_t, int64_t) +- +-#define VSSRANU(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = do_ssranu_ ## E1(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT, \ +- BIT / 2); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSSRANU(vssran_bu_h, 16, B, H, UH) +-VSSRANU(vssran_hu_w, 32, H, W, UW) +-VSSRANU(vssran_wu_d, 64, W, D, UD) +- +-#define VSSRLNI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = do_ssrlns_ ## E1(Vj->E2(j + ofs * i), \ +- imm, BIT / 2 - 1); \ +- temp.E1(j + ofs * (2 * i + 1)) = do_ssrlns_ ## E1(Vd->E2(j + ofs * i), \ +- imm, BIT / 2 - 1); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-static void do_vssrlni_q(VReg *Vd, VReg *Vj, +- uint64_t imm, int idx, Int128 mask) +-{ +- Int128 shft_res1, shft_res2; +- +- if (imm == 0) { +- shft_res1 = Vj->Q(idx); +- shft_res2 = Vd->Q(idx); +- } else { +- shft_res1 = int128_urshift(Vj->Q(idx), imm); +- shft_res2 = int128_urshift(Vd->Q(idx), imm); +- } +- +- if (int128_ult(mask, shft_res1)) { +- Vd->D(idx * 2) = int128_getlo(mask); +- }else { +- Vd->D(idx * 2) = int128_getlo(shft_res1); +- } +- +- if (int128_ult(mask, shft_res2)) { +- Vd->D(idx * 2 + 1) = int128_getlo(mask); +- }else { +- Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); +- } +-} +- +-void HELPER(vssrlni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- Int128 mask; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- mask = int128_sub(int128_lshift(int128_one(), 63), int128_one()); +- +- for (i = 0; i < oprsz / 16; i++) { +- do_vssrlni_q(Vd, Vj, imm, i, mask); +- } +-} +- +-VSSRLNI(vssrlni_b_h, 16, B, H) +-VSSRLNI(vssrlni_h_w, 32, H, W) +-VSSRLNI(vssrlni_w_d, 64, W, D) +- +-#define VSSRANI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = do_ssrans_ ## E1(Vj->E2(j + ofs * i), \ +- imm, BIT / 2 - 1); \ +- temp.E1(j + ofs * (2 * i + 1)) = do_ssrans_ ## E1(Vd->E2(j + ofs * i), \ +- imm, BIT / 2 - 1); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-static void do_vssrani_d_q(VReg *Vd, VReg *Vj, +- uint64_t imm, int idx, Int128 mask, Int128 min) +-{ +- Int128 shft_res1, shft_res2; +- +- if (imm == 0) { +- shft_res1 = Vj->Q(idx); +- shft_res2 = Vd->Q(idx); +- } else { +- shft_res1 = int128_rshift(Vj->Q(idx), imm); +- shft_res2 = int128_rshift(Vd->Q(idx), imm); +- } +- +- if (int128_gt(shft_res1, mask)) { +- Vd->D(idx * 2) = int128_getlo(mask); +- } else if (int128_lt(shft_res1, int128_neg(min))) { +- Vd->D(idx * 2) = int128_getlo(min); +- } else { +- Vd->D(idx * 2) = int128_getlo(shft_res1); +- } +- +- if (int128_gt(shft_res2, mask)) { +- Vd->D(idx * 2 + 1) = int128_getlo(mask); +- } else if (int128_lt(shft_res2, int128_neg(min))) { +- Vd->D(idx * 2 + 1) = int128_getlo(min); +- } else { +- Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); +- } +-} +- +-void HELPER(vssrani_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- Int128 mask, min; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- mask = int128_sub(int128_lshift(int128_one(), 63), int128_one()); +- min = int128_lshift(int128_one(), 63); +- +- for (i = 0; i < oprsz / 16; i++) { +- do_vssrani_d_q(Vd, Vj, imm, i, mask, min); +- } +-} +- +- +-VSSRANI(vssrani_b_h, 16, B, H) +-VSSRANI(vssrani_h_w, 32, H, W) +-VSSRANI(vssrani_w_d, 64, W, D) +- +-#define VSSRLNUI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = do_ssrlnu_ ## E1(Vj->E2(j + ofs * i), \ +- imm, BIT / 2); \ +- temp.E1(j + ofs * (2 * i + 1)) = do_ssrlnu_ ## E1(Vd->E2(j + ofs * i), \ +- imm, BIT / 2); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-void HELPER(vssrlni_du_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- Int128 mask; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- mask = int128_sub(int128_lshift(int128_one(), 64), int128_one()); +- +- for (i = 0; i < oprsz / 16; i++) { +- do_vssrlni_q(Vd, Vj, imm, i, mask); +- } +-} +- +-VSSRLNUI(vssrlni_bu_h, 16, B, H) +-VSSRLNUI(vssrlni_hu_w, 32, H, W) +-VSSRLNUI(vssrlni_wu_d, 64, W, D) +- +-#define VSSRANUI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = do_ssranu_ ## E1(Vj->E2(j + ofs * i), \ +- imm, BIT / 2); \ +- temp.E1(j + ofs * (2 * i + 1)) = do_ssranu_ ## E1(Vd->E2(j + ofs * i), \ +- imm, BIT / 2); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-static void do_vssrani_du_q(VReg *Vd, VReg *Vj, +- uint64_t imm, int idx, Int128 mask) +-{ +- Int128 shft_res1, shft_res2; +- +- if (imm == 0) { +- shft_res1 = Vj->Q(idx); +- shft_res2 = Vd->Q(idx); +- } else { +- shft_res1 = int128_rshift(Vj->Q(idx), imm); +- shft_res2 = int128_rshift(Vd->Q(idx), imm); +- } +- +- if (int128_lt(Vj->Q(idx), int128_zero())) { +- shft_res1 = int128_zero(); +- } +- +- if (int128_lt(Vd->Q(idx), int128_zero())) { +- shft_res2 = int128_zero(); +- } +- if (int128_ult(mask, shft_res1)) { +- Vd->D(idx * 2) = int128_getlo(mask); +- }else { +- Vd->D(idx * 2) = int128_getlo(shft_res1); +- } +- +- if (int128_ult(mask, shft_res2)) { +- Vd->D(idx * 2 + 1) = int128_getlo(mask); +- }else { +- Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); +- } +- +-} +- +-void HELPER(vssrani_du_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- Int128 mask; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- mask = int128_sub(int128_lshift(int128_one(), 64), int128_one()); +- +- for (i = 0; i < oprsz / 16; i++) { +- do_vssrani_du_q(Vd, Vj, imm, i, mask); +- } +-} +- +-VSSRANUI(vssrani_bu_h, 16, B, H) +-VSSRANUI(vssrani_hu_w, 32, H, W) +-VSSRANUI(vssrani_wu_d, 64, W, D) +- +-#define SSRLRNS(E1, E2, T1, T2, T3) \ +-static T1 do_ssrlrns_ ## E1(T2 e2, int sa, int sh) \ +-{ \ +- T1 shft_res; \ +- \ +- shft_res = do_vsrlr_ ## E2(e2, sa); \ +- T1 mask; \ +- mask = (1ull << sh) - 1; \ +- if (shft_res > mask) { \ +- return mask; \ +- } else { \ +- return shft_res; \ +- } \ +-} +- +-SSRLRNS(B, H, uint16_t, int16_t, uint8_t) +-SSRLRNS(H, W, uint32_t, int32_t, uint16_t) +-SSRLRNS(W, D, uint64_t, int64_t, uint32_t) +- +-#define VSSRLRN(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = do_ssrlrns_ ## E1(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT, \ +- BIT / 2 - 1); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSSRLRN(vssrlrn_b_h, 16, B, H, UH) +-VSSRLRN(vssrlrn_h_w, 32, H, W, UW) +-VSSRLRN(vssrlrn_w_d, 64, W, D, UD) +- +-#define SSRARNS(E1, E2, T1, T2) \ +-static T1 do_ssrarns_ ## E1(T1 e2, int sa, int sh) \ +-{ \ +- T1 shft_res; \ +- \ +- shft_res = do_vsrar_ ## E2(e2, sa); \ +- T2 mask; \ +- mask = (1ll << sh) - 1; \ +- if (shft_res > mask) { \ +- return mask; \ +- } else if (shft_res < -(mask +1)) { \ +- return ~mask; \ +- } else { \ +- return shft_res; \ +- } \ +-} +- +-SSRARNS(B, H, int16_t, int8_t) +-SSRARNS(H, W, int32_t, int16_t) +-SSRARNS(W, D, int64_t, int32_t) +- +-#define VSSRARN(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = do_ssrarns_ ## E1(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT, \ +- BIT/ 2 - 1); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSSRARN(vssrarn_b_h, 16, B, H, UH) +-VSSRARN(vssrarn_h_w, 32, H, W, UW) +-VSSRARN(vssrarn_w_d, 64, W, D, UD) +- +-#define SSRLRNU(E1, E2, T1, T2, T3) \ +-static T1 do_ssrlrnu_ ## E1(T3 e2, int sa, int sh) \ +-{ \ +- T1 shft_res; \ +- \ +- shft_res = do_vsrlr_ ## E2(e2, sa); \ +- \ +- T2 mask; \ +- mask = (1ull << sh) - 1; \ +- if (shft_res > mask) { \ +- return mask; \ +- } else { \ +- return shft_res; \ +- } \ +-} +- +-SSRLRNU(B, H, uint16_t, uint8_t, int16_t) +-SSRLRNU(H, W, uint32_t, uint16_t, int32_t) +-SSRLRNU(W, D, uint64_t, uint32_t, int64_t) +- +-#define VSSRLRNU(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = do_ssrlrnu_ ## E1(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT, \ +- BIT / 2); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSSRLRNU(vssrlrn_bu_h, 16, B, H, UH) +-VSSRLRNU(vssrlrn_hu_w, 32, H, W, UW) +-VSSRLRNU(vssrlrn_wu_d, 64, W, D, UD) +- +-#define SSRARNU(E1, E2, T1, T2, T3) \ +-static T1 do_ssrarnu_ ## E1(T3 e2, int sa, int sh) \ +-{ \ +- T1 shft_res; \ +- \ +- if (e2 < 0) { \ +- shft_res = 0; \ +- } else { \ +- shft_res = do_vsrar_ ## E2(e2, sa); \ +- } \ +- T2 mask; \ +- mask = (1ull << sh) - 1; \ +- if (shft_res > mask) { \ +- return mask; \ +- } else { \ +- return shft_res; \ +- } \ +-} +- +-SSRARNU(B, H, uint16_t, uint8_t, int16_t) +-SSRARNU(H, W, uint32_t, uint16_t, int32_t) +-SSRARNU(W, D, uint64_t, uint32_t, int64_t) +- +-#define VSSRARNU(NAME, BIT, E1, E2, E3) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- Vd->E1(j + ofs * 2 * i) = do_ssrarnu_ ## E1(Vj->E2(j + ofs * i), \ +- Vk->E3(j + ofs * i) % BIT, \ +- BIT / 2); \ +- } \ +- Vd->D(2 * i + 1) = 0; \ +- } \ +-} +- +-VSSRARNU(vssrarn_bu_h, 16, B, H, UH) +-VSSRARNU(vssrarn_hu_w, 32, H, W, UW) +-VSSRARNU(vssrarn_wu_d, 64, W, D, UD) +- +-#define VSSRLRNI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = do_ssrlrns_ ## E1(Vj->E2(j + ofs * i), \ +- imm, BIT / 2 - 1); \ +- temp.E1(j + ofs * (2 * i + 1)) = do_ssrlrns_ ## E1(Vd->E2(j + ofs * i), \ +- imm, BIT / 2 - 1); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-static void do_vssrlrni_q(VReg *Vd, VReg * Vj, +- uint64_t imm, int idx, Int128 mask) +-{ +- Int128 shft_res1, shft_res2, r1, r2; +- if (imm == 0) { +- shft_res1 = Vj->Q(idx); +- shft_res2 = Vd->Q(idx); +- } else { +- r1 = int128_and(int128_urshift(Vj->Q(idx), (imm - 1)), int128_one()); +- r2 = int128_and(int128_urshift(Vd->Q(idx), (imm - 1)), int128_one()); +- shft_res1 = (int128_add(int128_urshift(Vj->Q(idx), imm), r1)); +- shft_res2 = (int128_add(int128_urshift(Vd->Q(idx), imm), r2)); +- } +- +- if (int128_ult(mask, shft_res1)) { +- Vd->D(idx * 2) = int128_getlo(mask); +- }else { +- Vd->D(idx * 2) = int128_getlo(shft_res1); +- } +- +- if (int128_ult(mask, shft_res2)) { +- Vd->D(idx * 2 + 1) = int128_getlo(mask); +- }else { +- Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); +- } +-} +- +-void HELPER(vssrlrni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- Int128 mask; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- mask = int128_sub(int128_lshift(int128_one(), 63), int128_one()); +- +- for (i = 0; i < oprsz / 16; i++) { +- do_vssrlrni_q(Vd, Vj, imm, i, mask); +- } +-} +- +-VSSRLRNI(vssrlrni_b_h, 16, B, H) +-VSSRLRNI(vssrlrni_h_w, 32, H, W) +-VSSRLRNI(vssrlrni_w_d, 64, W, D) +- +-#define VSSRARNI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = do_ssrarns_ ## E1(Vj->E2(j + ofs * i), \ +- imm, BIT / 2 - 1); \ +- temp.E1(j + ofs * (2 * i + 1)) = do_ssrarns_ ## E1(Vd->E2(j + ofs * i), \ +- imm, BIT / 2 - 1); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-static void do_vssrarni_d_q(VReg *Vd, VReg *Vj, +- uint64_t imm, int idx, Int128 mask1, Int128 mask2) +-{ +- Int128 shft_res1, shft_res2, r1, r2; +- +- if (imm == 0) { +- shft_res1 = Vj->Q(idx); +- shft_res2 = Vd->Q(idx); +- } else { +- r1 = int128_and(int128_rshift(Vj->Q(idx), (imm - 1)), int128_one()); +- r2 = int128_and(int128_rshift(Vd->Q(idx), (imm - 1)), int128_one()); +- shft_res1 = int128_add(int128_rshift(Vj->Q(idx), imm), r1); +- shft_res2 = int128_add(int128_rshift(Vd->Q(idx), imm), r2); +- } +- if (int128_gt(shft_res1, mask1)) { +- Vd->D(idx * 2) = int128_getlo(mask1); +- } else if (int128_lt(shft_res1, int128_neg(mask2))) { +- Vd->D(idx * 2) = int128_getlo(mask2); +- } else { +- Vd->D(idx * 2) = int128_getlo(shft_res1); +- } +- +- if (int128_gt(shft_res2, mask1)) { +- Vd->D(idx * 2 + 1) = int128_getlo(mask1); +- } else if (int128_lt(shft_res2, int128_neg(mask2))) { +- Vd->D(idx * 2 + 1) = int128_getlo(mask2); +- } else { +- Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); +- } +-} +- +-void HELPER(vssrarni_d_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- Int128 mask1, mask2; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- mask1 = int128_sub(int128_lshift(int128_one(), 63), int128_one()); +- mask2 = int128_lshift(int128_one(), 63); +- +- for (i = 0; i < oprsz / 16; i++) { +- do_vssrarni_d_q(Vd, Vj, imm, i, mask1, mask2); +- } +-} +- +-VSSRARNI(vssrarni_b_h, 16, B, H) +-VSSRARNI(vssrarni_h_w, 32, H, W) +-VSSRARNI(vssrarni_w_d, 64, W, D) +- +-#define VSSRLRNUI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = do_ssrlrnu_ ## E1(Vj->E2(j + ofs * i), \ +- imm, BIT / 2); \ +- temp.E1(j + ofs * (2 * i + 1)) = do_ssrlrnu_ ## E1(Vd->E2(j + ofs * i), \ +- imm, BIT / 2); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-void HELPER(vssrlrni_du_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- Int128 mask; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- mask = int128_sub(int128_lshift(int128_one(), 64), int128_one()); +- +- for (i = 0; i < oprsz / 16; i++) { +- do_vssrlrni_q(Vd, Vj, imm, i, mask); +- } +-} +- +-VSSRLRNUI(vssrlrni_bu_h, 16, B, H) +-VSSRLRNUI(vssrlrni_hu_w, 32, H, W) +-VSSRLRNUI(vssrlrni_wu_d, 64, W, D) +- +-#define VSSRARNUI(NAME, BIT, E1, E2) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E1(j + ofs * 2 * i) = do_ssrarnu_ ## E1(Vj->E2(j + ofs * i), \ +- imm, BIT / 2); \ +- temp.E1(j + ofs * (2 * i + 1)) = do_ssrarnu_ ## E1(Vd->E2(j + ofs * i), \ +- imm, BIT / 2); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-static void do_vssrarni_du_q(VReg *Vd, VReg *Vj, +- uint64_t imm, int idx, Int128 mask1, Int128 mask2) +-{ +- Int128 shft_res1, shft_res2, r1, r2; +- +- if (imm == 0) { +- shft_res1 = Vj->Q(idx); +- shft_res2 = Vd->Q(idx); +- } else { +- r1 = int128_and(int128_rshift(Vj->Q(idx), (imm - 1)), int128_one()); +- r2 = int128_and(int128_rshift(Vd->Q(idx), (imm - 1)), int128_one()); +- shft_res1 = int128_add(int128_rshift(Vj->Q(idx), imm), r1); +- shft_res2 = int128_add(int128_rshift(Vd->Q(idx), imm), r2); +- } +- +- if (int128_lt(Vj->Q(idx), int128_zero())) { +- shft_res1 = int128_zero(); +- } +- if (int128_lt(Vd->Q(idx), int128_zero())) { +- shft_res2 = int128_zero(); +- } +- +- if (int128_gt(shft_res1, mask1)) { +- Vd->D(idx * 2) = int128_getlo(mask1); +- } else if (int128_lt(shft_res1, int128_neg(mask2))) { +- Vd->D(idx * 2) = int128_getlo(mask2); +- } else { +- Vd->D(idx * 2) = int128_getlo(shft_res1); +- } +- +- if (int128_gt(shft_res2, mask1)) { +- Vd->D(idx * 2 + 1) = int128_getlo(mask1); +- } else if (int128_lt(shft_res2, int128_neg(mask2))) { +- Vd->D(idx * 2 + 1) = int128_getlo(mask2); +- } else { +- Vd->D(idx * 2 + 1) = int128_getlo(shft_res2); +- } +-} +- +-void HELPER(vssrarni_du_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- Int128 mask1, mask2; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- mask1 = int128_sub(int128_lshift(int128_one(), 64), int128_one()); +- mask2 = int128_lshift(int128_one(), 64); +- +- for (i = 0; i < oprsz / 16; i++) { +- do_vssrarni_du_q(Vd, Vj, imm, i, mask1, mask2); +- } +-} +- +-VSSRARNUI(vssrarni_bu_h, 16, B, H) +-VSSRARNUI(vssrarni_hu_w, 32, H, W) +-VSSRARNUI(vssrarni_wu_d, 64, W, D) +- +-#define DO_2OP(NAME, BIT, E, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) \ +- { \ +- Vd->E(i) = DO_OP(Vj->E(i)); \ +- } \ +-} +- +-DO_2OP(vclo_b, 8, UB, DO_CLO_B) +-DO_2OP(vclo_h, 16, UH, DO_CLO_H) +-DO_2OP(vclo_w, 32, UW, DO_CLO_W) +-DO_2OP(vclo_d, 64, UD, DO_CLO_D) +-DO_2OP(vclz_b, 8, UB, DO_CLZ_B) +-DO_2OP(vclz_h, 16, UH, DO_CLZ_H) +-DO_2OP(vclz_w, 32, UW, DO_CLZ_W) +-DO_2OP(vclz_d, 64, UD, DO_CLZ_D) +- +-#define VPCNT(NAME, BIT, E, FN) \ +-void HELPER(NAME)(void *vd, void *vj, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) \ +- { \ +- Vd->E(i) = FN(Vj->E(i)); \ +- } \ +-} +- +-VPCNT(vpcnt_b, 8, UB, ctpop8) +-VPCNT(vpcnt_h, 16, UH, ctpop16) +-VPCNT(vpcnt_w, 32, UW, ctpop32) +-VPCNT(vpcnt_d, 64, UD, ctpop64) +- +-#define DO_BIT(NAME, BIT, E, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = DO_OP(Vj->E(i), Vk->E(i)%BIT); \ +- } \ +-} +- +-DO_BIT(vbitclr_b, 8, UB, DO_BITCLR) +-DO_BIT(vbitclr_h, 16, UH, DO_BITCLR) +-DO_BIT(vbitclr_w, 32, UW, DO_BITCLR) +-DO_BIT(vbitclr_d, 64, UD, DO_BITCLR) +-DO_BIT(vbitset_b, 8, UB, DO_BITSET) +-DO_BIT(vbitset_h, 16, UH, DO_BITSET) +-DO_BIT(vbitset_w, 32, UW, DO_BITSET) +-DO_BIT(vbitset_d, 64, UD, DO_BITSET) +-DO_BIT(vbitrev_b, 8, UB, DO_BITREV) +-DO_BIT(vbitrev_h, 16, UH, DO_BITREV) +-DO_BIT(vbitrev_w, 32, UW, DO_BITREV) +-DO_BIT(vbitrev_d, 64, UD, DO_BITREV) +- +-#define DO_BITI(NAME, BIT, E, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = DO_OP(Vj->E(i), imm); \ +- } \ +-} +- +-DO_BITI(vbitclri_b, 8, UB, DO_BITCLR) +-DO_BITI(vbitclri_h, 16, UH, DO_BITCLR) +-DO_BITI(vbitclri_w, 32, UW, DO_BITCLR) +-DO_BITI(vbitclri_d, 64, UD, DO_BITCLR) +-DO_BITI(vbitseti_b, 8, UB, DO_BITSET) +-DO_BITI(vbitseti_h, 16, UH, DO_BITSET) +-DO_BITI(vbitseti_w, 32, UW, DO_BITSET) +-DO_BITI(vbitseti_d, 64, UD, DO_BITSET) +-DO_BITI(vbitrevi_b, 8, UB, DO_BITREV) +-DO_BITI(vbitrevi_h, 16, UH, DO_BITREV) +-DO_BITI(vbitrevi_w, 32, UW, DO_BITREV) +-DO_BITI(vbitrevi_d, 64, UD, DO_BITREV) +- +-#define VFRSTP(NAME, BIT, MASK, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, m, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- m = Vk->E(i * ofs) & MASK; \ +- for (j = 0; j < ofs; j++) { \ +- if (Vj->E(j + ofs * i) < 0) { \ +- break; \ +- } \ +- } \ +- Vd->E(m + i * ofs) = j; \ +- } \ +-} +- +-VFRSTP(vfrstp_b, 8, 0xf, B) +-VFRSTP(vfrstp_h, 16, 0x7, H) +- +-#define VFRSTPI(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, m, ofs; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- m = imm % ofs; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- if (Vj->E(j + ofs * i) < 0) { \ +- break; \ +- } \ +- } \ +- Vd->E(m + i * ofs) = j; \ +- } \ +-} +- +-VFRSTPI(vfrstpi_b, 8, B) +-VFRSTPI(vfrstpi_h, 16, H) +- +-static void vec_update_fcsr0_mask(CPULoongArchState *env, +- uintptr_t pc, int mask) +-{ +- int flags = get_float_exception_flags(&env->fp_status); +- +- set_float_exception_flags(0, &env->fp_status); +- +- flags &= ~mask; +- +- if (flags) { +- flags = ieee_ex_to_loongarch(flags); +- UPDATE_FP_CAUSE(env->fcsr0, flags); +- } +- +- if (GET_FP_ENABLES(env->fcsr0) & flags) { +- do_raise_exception(env, EXCCODE_FPE, pc); +- } else { +- UPDATE_FP_FLAGS(env->fcsr0, flags); +- } +-} +- +-static void vec_update_fcsr0(CPULoongArchState *env, uintptr_t pc) +-{ +- vec_update_fcsr0_mask(env, pc, 0); +-} +- +-static inline void vec_clear_cause(CPULoongArchState *env) +-{ +- SET_FP_CAUSE(env->fcsr0, 0); +-} +- +-#define DO_3OP_F(NAME, BIT, E, FN) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, \ +- CPULoongArchState *env, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- vec_clear_cause(env); \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = FN(Vj->E(i), Vk->E(i), &env->fp_status); \ +- vec_update_fcsr0(env, GETPC()); \ +- } \ +-} +- +-DO_3OP_F(vfadd_s, 32, UW, float32_add) +-DO_3OP_F(vfadd_d, 64, UD, float64_add) +-DO_3OP_F(vfsub_s, 32, UW, float32_sub) +-DO_3OP_F(vfsub_d, 64, UD, float64_sub) +-DO_3OP_F(vfmul_s, 32, UW, float32_mul) +-DO_3OP_F(vfmul_d, 64, UD, float64_mul) +-DO_3OP_F(vfdiv_s, 32, UW, float32_div) +-DO_3OP_F(vfdiv_d, 64, UD, float64_div) +-DO_3OP_F(vfmax_s, 32, UW, float32_maxnum) +-DO_3OP_F(vfmax_d, 64, UD, float64_maxnum) +-DO_3OP_F(vfmin_s, 32, UW, float32_minnum) +-DO_3OP_F(vfmin_d, 64, UD, float64_minnum) +-DO_3OP_F(vfmaxa_s, 32, UW, float32_maxnummag) +-DO_3OP_F(vfmaxa_d, 64, UD, float64_maxnummag) +-DO_3OP_F(vfmina_s, 32, UW, float32_minnummag) +-DO_3OP_F(vfmina_d, 64, UD, float64_minnummag) +- +-#define DO_4OP_F(NAME, BIT, E, FN, flags) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, void *va, \ +- CPULoongArchState *env, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- VReg *Va = (VReg *)va; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- vec_clear_cause(env); \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = FN(Vj->E(i), Vk->E(i), Va->E(i), flags, &env->fp_status); \ +- vec_update_fcsr0(env, GETPC()); \ +- } \ +-} +- +-DO_4OP_F(vfmadd_s, 32, UW, float32_muladd, 0) +-DO_4OP_F(vfmadd_d, 64, UD, float64_muladd, 0) +-DO_4OP_F(vfmsub_s, 32, UW, float32_muladd, float_muladd_negate_c) +-DO_4OP_F(vfmsub_d, 64, UD, float64_muladd, float_muladd_negate_c) +-DO_4OP_F(vfnmadd_s, 32, UW, float32_muladd, float_muladd_negate_result) +-DO_4OP_F(vfnmadd_d, 64, UD, float64_muladd, float_muladd_negate_result) +-DO_4OP_F(vfnmsub_s, 32, UW, float32_muladd, +- float_muladd_negate_c | float_muladd_negate_result) +-DO_4OP_F(vfnmsub_d, 64, UD, float64_muladd, +- float_muladd_negate_c | float_muladd_negate_result) +- +-#define DO_2OP_F(NAME, BIT, E, FN) \ +-void HELPER(NAME)(void *vd, void *vj, \ +- CPULoongArchState *env, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- vec_clear_cause(env); \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = FN(env, Vj->E(i)); \ +- } \ +-} +- +-#define FLOGB(BIT, T) \ +-static T do_flogb_## BIT(CPULoongArchState *env, T fj) \ +-{ \ +- T fp, fd; \ +- float_status *status = &env->fp_status; \ +- FloatRoundMode old_mode = get_float_rounding_mode(status); \ +- \ +- set_float_rounding_mode(float_round_down, status); \ +- fp = float ## BIT ##_log2(fj, status); \ +- fd = float ## BIT ##_round_to_int(fp, status); \ +- set_float_rounding_mode(old_mode, status); \ +- vec_update_fcsr0_mask(env, GETPC(), float_flag_inexact); \ +- return fd; \ +-} +- +-FLOGB(32, uint32_t) +-FLOGB(64, uint64_t) +- +-#define FCLASS(NAME, BIT, E, FN) \ +-void HELPER(NAME)(void *vd, void *vj, \ +- CPULoongArchState *env, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = FN(env, Vj->E(i)); \ +- } \ +-} +- +-FCLASS(vfclass_s, 32, UW, helper_fclass_s) +-FCLASS(vfclass_d, 64, UD, helper_fclass_d) +- +-#define FSQRT(BIT, T) \ +-static T do_fsqrt_## BIT(CPULoongArchState *env, T fj) \ +-{ \ +- T fd; \ +- fd = float ## BIT ##_sqrt(fj, &env->fp_status); \ +- vec_update_fcsr0(env, GETPC()); \ +- return fd; \ +-} +- +-FSQRT(32, uint32_t) +-FSQRT(64, uint64_t) +- +-#define FRECIP(BIT, T) \ +-static T do_frecip_## BIT(CPULoongArchState *env, T fj) \ +-{ \ +- T fd; \ +- fd = float ## BIT ##_div(float ## BIT ##_one, fj, &env->fp_status); \ +- vec_update_fcsr0(env, GETPC()); \ +- return fd; \ +-} +- +-FRECIP(32, uint32_t) +-FRECIP(64, uint64_t) +- +-#define FRSQRT(BIT, T) \ +-static T do_frsqrt_## BIT(CPULoongArchState *env, T fj) \ +-{ \ +- T fd, fp; \ +- fp = float ## BIT ##_sqrt(fj, &env->fp_status); \ +- fd = float ## BIT ##_div(float ## BIT ##_one, fp, &env->fp_status); \ +- vec_update_fcsr0(env, GETPC()); \ +- return fd; \ +-} +- +-FRSQRT(32, uint32_t) +-FRSQRT(64, uint64_t) +- +-DO_2OP_F(vflogb_s, 32, UW, do_flogb_32) +-DO_2OP_F(vflogb_d, 64, UD, do_flogb_64) +-DO_2OP_F(vfsqrt_s, 32, UW, do_fsqrt_32) +-DO_2OP_F(vfsqrt_d, 64, UD, do_fsqrt_64) +-DO_2OP_F(vfrecip_s, 32, UW, do_frecip_32) +-DO_2OP_F(vfrecip_d, 64, UD, do_frecip_64) +-DO_2OP_F(vfrsqrt_s, 32, UW, do_frsqrt_32) +-DO_2OP_F(vfrsqrt_d, 64, UD, do_frsqrt_64) +- +-static uint32_t float16_cvt_float32(uint16_t h, float_status *status) +-{ +- return float16_to_float32(h, true, status); +-} +-static uint64_t float32_cvt_float64(uint32_t s, float_status *status) +-{ +- return float32_to_float64(s, status); +-} +- +-static uint16_t float32_cvt_float16(uint32_t s, float_status *status) +-{ +- return float32_to_float16(s, true, status); +-} +-static uint32_t float64_cvt_float32(uint64_t d, float_status *status) +-{ +- return float64_to_float32(d, status); +-} +- +-void HELPER(vfcvtl_s_h)(void *vd, void *vj, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i, j, ofs; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- ofs = LSX_LEN / 32; +- vec_clear_cause(env); +- for (i = 0; i < oprsz / 16; i++) { +- for (j = 0; j < ofs; j++) { +- temp.UW(j + ofs * i) =float16_cvt_float32(Vj->UH(j + ofs * 2 * i), +- &env->fp_status); +- } +- vec_update_fcsr0(env, GETPC()); +- } +- *Vd = temp; +-} +- +-void HELPER(vfcvtl_d_s)(void *vd, void *vj, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i, j, ofs; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- ofs = LSX_LEN / 64; +- vec_clear_cause(env); +- for (i = 0; i < oprsz / 16; i++) { +- for (j = 0; j < ofs; j++) { +- temp.UD(j + ofs * i) = float32_cvt_float64(Vj->UW(j + ofs * 2 * i), +- &env->fp_status); +- } +- vec_update_fcsr0(env, GETPC()); +- } +- *Vd = temp; +-} +- +-void HELPER(vfcvth_s_h)(void *vd, void *vj, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i, j, ofs; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- ofs = LSX_LEN / 32; +- vec_clear_cause(env); +- for (i = 0; i < oprsz / 16; i++) { +- for (j = 0; j < ofs; j++) { +- temp.UW(j + ofs * i) = float16_cvt_float32(Vj->UH(j + ofs * (2 * i + 1)), +- &env->fp_status); +- } +- vec_update_fcsr0(env, GETPC()); +- } +- *Vd = temp; +-} +- +-void HELPER(vfcvth_d_s)(void *vd, void *vj, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i, j, ofs; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- ofs = LSX_LEN / 64; +- vec_clear_cause(env); +- for (i = 0; i < oprsz / 16; i++) { +- for (j = 0; j < ofs; j++) { +- temp.UD(j + ofs * i) = float32_cvt_float64(Vj->UW(j + ofs * (2 * i + 1)), +- &env->fp_status); +- } +- vec_update_fcsr0(env, GETPC()); +- } +- *Vd = temp; +-} +- +-void HELPER(vfcvt_h_s)(void *vd, void *vj, void *vk, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i, j, ofs; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- ofs = LSX_LEN / 32; +- vec_clear_cause(env); +- for(i = 0; i < oprsz / 16; i++) { +- for (j = 0; j < ofs; j++) { +- temp.UH(j + ofs * (2 * i + 1)) = float32_cvt_float16(Vj->UW(j + ofs * i), +- &env->fp_status); +- temp.UH(j + ofs * 2 * i) = float32_cvt_float16(Vk->UW(j + ofs * i), +- &env->fp_status); +- } +- vec_update_fcsr0(env, GETPC()); +- } +- *Vd = temp; +-} +- +-void HELPER(vfcvt_s_d)(void *vd, void *vj, void *vk, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i, j, ofs; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- ofs = LSX_LEN / 64; +- vec_clear_cause(env); +- for(i = 0; i < oprsz / 16; i++) { +- for (j = 0; j < ofs; j++) { +- temp.UW(j + ofs * (2 * i + 1)) = float64_cvt_float32(Vj->UD(j + ofs * i), +- &env->fp_status); +- temp.UW(j + ofs * 2 * i) = float64_cvt_float32(Vk->UD(j + ofs * i), +- &env->fp_status); +- } +- vec_update_fcsr0(env, GETPC()); +- } +- *Vd = temp; +-} +- +-void HELPER(vfrint_s)(void *vd, void *vj, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- vec_clear_cause(env); +- for (i = 0; i < oprsz / 4; i++) { +- Vd->W(i) = float32_round_to_int(Vj->UW(i), &env->fp_status); +- vec_update_fcsr0(env, GETPC()); +- } +-} +- +-void HELPER(vfrint_d)(void *vd, void *vj, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- vec_clear_cause(env); +- for (i = 0; i < oprsz / 8; i++) { +- Vd->D(i) = float64_round_to_int(Vj->UD(i), &env->fp_status); +- vec_update_fcsr0(env, GETPC()); +- } +-} +- +-#define FCVT_2OP(NAME, BIT, E, MODE) \ +-void HELPER(NAME)(void *vd, void *vj, \ +- CPULoongArchState *env, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- vec_clear_cause(env); \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); \ +- set_float_rounding_mode(MODE, &env->fp_status); \ +- Vd->E(i) = float## BIT ## _round_to_int(Vj->E(i), &env->fp_status); \ +- set_float_rounding_mode(old_mode, &env->fp_status); \ +- vec_update_fcsr0(env, GETPC()); \ +- } \ +-} +- +-FCVT_2OP(vfrintrne_s, 32, UW, float_round_nearest_even) +-FCVT_2OP(vfrintrne_d, 64, UD, float_round_nearest_even) +-FCVT_2OP(vfrintrz_s, 32, UW, float_round_to_zero) +-FCVT_2OP(vfrintrz_d, 64, UD, float_round_to_zero) +-FCVT_2OP(vfrintrp_s, 32, UW, float_round_up) +-FCVT_2OP(vfrintrp_d, 64, UD, float_round_up) +-FCVT_2OP(vfrintrm_s, 32, UW, float_round_down) +-FCVT_2OP(vfrintrm_d, 64, UD, float_round_down) +- +-#define FTINT(NAME, FMT1, FMT2, T1, T2, MODE) \ +-static T2 do_ftint ## NAME(CPULoongArchState *env, T1 fj) \ +-{ \ +- T2 fd; \ +- FloatRoundMode old_mode = get_float_rounding_mode(&env->fp_status); \ +- \ +- set_float_rounding_mode(MODE, &env->fp_status); \ +- fd = do_## FMT1 ##_to_## FMT2(env, fj); \ +- set_float_rounding_mode(old_mode, &env->fp_status); \ +- return fd; \ +-} +- +-#define DO_FTINT(FMT1, FMT2, T1, T2) \ +-static T2 do_## FMT1 ##_to_## FMT2(CPULoongArchState *env, T1 fj) \ +-{ \ +- T2 fd; \ +- \ +- fd = FMT1 ##_to_## FMT2(fj, &env->fp_status); \ +- if (get_float_exception_flags(&env->fp_status) & (float_flag_invalid)) { \ +- if (FMT1 ##_is_any_nan(fj)) { \ +- fd = 0; \ +- } \ +- } \ +- vec_update_fcsr0(env, GETPC()); \ +- return fd; \ +-} +- +-DO_FTINT(float32, int32, uint32_t, uint32_t) +-DO_FTINT(float64, int64, uint64_t, uint64_t) +-DO_FTINT(float32, uint32, uint32_t, uint32_t) +-DO_FTINT(float64, uint64, uint64_t, uint64_t) +-DO_FTINT(float64, int32, uint64_t, uint32_t) +-DO_FTINT(float32, int64, uint32_t, uint64_t) +- +-FTINT(rne_w_s, float32, int32, uint32_t, uint32_t, float_round_nearest_even) +-FTINT(rne_l_d, float64, int64, uint64_t, uint64_t, float_round_nearest_even) +-FTINT(rp_w_s, float32, int32, uint32_t, uint32_t, float_round_up) +-FTINT(rp_l_d, float64, int64, uint64_t, uint64_t, float_round_up) +-FTINT(rz_w_s, float32, int32, uint32_t, uint32_t, float_round_to_zero) +-FTINT(rz_l_d, float64, int64, uint64_t, uint64_t, float_round_to_zero) +-FTINT(rm_w_s, float32, int32, uint32_t, uint32_t, float_round_down) +-FTINT(rm_l_d, float64, int64, uint64_t, uint64_t, float_round_down) +- +-DO_2OP_F(vftintrne_w_s, 32, UW, do_ftintrne_w_s) +-DO_2OP_F(vftintrne_l_d, 64, UD, do_ftintrne_l_d) +-DO_2OP_F(vftintrp_w_s, 32, UW, do_ftintrp_w_s) +-DO_2OP_F(vftintrp_l_d, 64, UD, do_ftintrp_l_d) +-DO_2OP_F(vftintrz_w_s, 32, UW, do_ftintrz_w_s) +-DO_2OP_F(vftintrz_l_d, 64, UD, do_ftintrz_l_d) +-DO_2OP_F(vftintrm_w_s, 32, UW, do_ftintrm_w_s) +-DO_2OP_F(vftintrm_l_d, 64, UD, do_ftintrm_l_d) +-DO_2OP_F(vftint_w_s, 32, UW, do_float32_to_int32) +-DO_2OP_F(vftint_l_d, 64, UD, do_float64_to_int64) +- +-FTINT(rz_wu_s, float32, uint32, uint32_t, uint32_t, float_round_to_zero) +-FTINT(rz_lu_d, float64, uint64, uint64_t, uint64_t, float_round_to_zero) +- +-DO_2OP_F(vftintrz_wu_s, 32, UW, do_ftintrz_wu_s) +-DO_2OP_F(vftintrz_lu_d, 64, UD, do_ftintrz_lu_d) +-DO_2OP_F(vftint_wu_s, 32, UW, do_float32_to_uint32) +-DO_2OP_F(vftint_lu_d, 64, UD, do_float64_to_uint64) +- +-FTINT(rm_w_d, float64, int32, uint64_t, uint32_t, float_round_down) +-FTINT(rp_w_d, float64, int32, uint64_t, uint32_t, float_round_up) +-FTINT(rz_w_d, float64, int32, uint64_t, uint32_t, float_round_to_zero) +-FTINT(rne_w_d, float64, int32, uint64_t, uint32_t, float_round_nearest_even) +- +-#define FTINT_W_D(NAME, FN) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, \ +- CPULoongArchState *env, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / 64; \ +- vec_clear_cause(env); \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.W(j + ofs * (2 * i + 1)) = FN(env, Vj->UD(j + ofs * i)); \ +- temp.W(j + ofs * 2 * i) = FN(env, Vk->UD(j + ofs * i)); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-FTINT_W_D(vftint_w_d, do_float64_to_int32) +-FTINT_W_D(vftintrm_w_d, do_ftintrm_w_d) +-FTINT_W_D(vftintrp_w_d, do_ftintrp_w_d) +-FTINT_W_D(vftintrz_w_d, do_ftintrz_w_d) +-FTINT_W_D(vftintrne_w_d, do_ftintrne_w_d) +- +-FTINT(rml_l_s, float32, int64, uint32_t, uint64_t, float_round_down) +-FTINT(rpl_l_s, float32, int64, uint32_t, uint64_t, float_round_up) +-FTINT(rzl_l_s, float32, int64, uint32_t, uint64_t, float_round_to_zero) +-FTINT(rnel_l_s, float32, int64, uint32_t, uint64_t, float_round_nearest_even) +-FTINT(rmh_l_s, float32, int64, uint32_t, uint64_t, float_round_down) +-FTINT(rph_l_s, float32, int64, uint32_t, uint64_t, float_round_up) +-FTINT(rzh_l_s, float32, int64, uint32_t, uint64_t, float_round_to_zero) +-FTINT(rneh_l_s, float32, int64, uint32_t, uint64_t, float_round_nearest_even) +- +-#define FTINTL_L_S(NAME, FN) \ +-void HELPER(NAME)(void *vd, void *vj, \ +- CPULoongArchState *env, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / 64; \ +- vec_clear_cause(env); \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.D(j + ofs * i) = FN(env, Vj->UW(j + ofs * 2 * i)); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-FTINTL_L_S(vftintl_l_s, do_float32_to_int64) +-FTINTL_L_S(vftintrml_l_s, do_ftintrml_l_s) +-FTINTL_L_S(vftintrpl_l_s, do_ftintrpl_l_s) +-FTINTL_L_S(vftintrzl_l_s, do_ftintrzl_l_s) +-FTINTL_L_S(vftintrnel_l_s, do_ftintrnel_l_s) +- +-#define FTINTH_L_S(NAME, FN) \ +-void HELPER(NAME)(void *vd, void *vj, \ +- CPULoongArchState *env, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / 64; \ +- vec_clear_cause(env); \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.D(j + ofs * i) = FN(env, Vj->UW(j + ofs * (2 * i + 1))); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-FTINTH_L_S(vftinth_l_s, do_float32_to_int64) +-FTINTH_L_S(vftintrmh_l_s, do_ftintrmh_l_s) +-FTINTH_L_S(vftintrph_l_s, do_ftintrph_l_s) +-FTINTH_L_S(vftintrzh_l_s, do_ftintrzh_l_s) +-FTINTH_L_S(vftintrneh_l_s, do_ftintrneh_l_s) +- +-#define FFINT(NAME, FMT1, FMT2, T1, T2) \ +-static T2 do_ffint_ ## NAME(CPULoongArchState *env, T1 fj) \ +-{ \ +- T2 fd; \ +- \ +- fd = FMT1 ##_to_## FMT2(fj, &env->fp_status); \ +- vec_update_fcsr0(env, GETPC()); \ +- return fd; \ +-} +- +-FFINT(s_w, int32, float32, int32_t, uint32_t) +-FFINT(d_l, int64, float64, int64_t, uint64_t) +-FFINT(s_wu, uint32, float32, uint32_t, uint32_t) +-FFINT(d_lu, uint64, float64, uint64_t, uint64_t) +- +-DO_2OP_F(vffint_s_w, 32, W, do_ffint_s_w) +-DO_2OP_F(vffint_d_l, 64, D, do_ffint_d_l) +-DO_2OP_F(vffint_s_wu, 32, UW, do_ffint_s_wu) +-DO_2OP_F(vffint_d_lu, 64, UD, do_ffint_d_lu) +- +-void HELPER(vffintl_d_w)(void *vd, void *vj, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i, j, ofs; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- ofs = LSX_LEN / 64; +- vec_clear_cause(env); +- for (i = 0; i < oprsz / 16; i++) { +- for (j = 0; j < ofs; j++) { +- temp.D(j + ofs * i) = int32_to_float64(Vj->W(j + ofs * 2 * i), +- &env->fp_status); +- } +- vec_update_fcsr0(env, GETPC()); +- } +- *Vd = temp; +-} +- +-void HELPER(vffinth_d_w)(void *vd, void *vj, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i, j, ofs; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- ofs = LSX_LEN / 64; +- vec_clear_cause(env); +- for (i = 0; i < oprsz /16; i++) { +- for (j = 0; j < ofs; j++) { +- temp.D(j + ofs * i) = int32_to_float64(Vj->W(j + ofs * (2 * i + 1)), +- &env->fp_status); +- } +- vec_update_fcsr0(env, GETPC()); +- } +- *Vd = temp; +-} +- +-void HELPER(vffint_s_l)(void *vd, void *vj, void *vk, +- CPULoongArchState *env, uint32_t desc) +-{ +- int i, j, ofs; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- int oprsz = simd_oprsz(desc); +- +- ofs = LSX_LEN / 64; +- vec_clear_cause(env); +- for (i = 0; i < oprsz / 16; i++) { +- for (j = 0; j < ofs; j++) { +- temp.W(j + ofs * (2 * i + 1)) = int64_to_float32(Vj->D(j + ofs * i), +- &env->fp_status); +- temp.W(j + ofs * 2 * i) = int64_to_float32(Vk->D(j + ofs * i), +- &env->fp_status); +- } +- vec_update_fcsr0(env, GETPC()); +- } +- *Vd = temp; +-} +- +-#define VCMPI(NAME, BIT, E, DO_OP) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- typedef __typeof(Vd->E(0)) TD; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = DO_OP(Vj->E(i), (TD)imm); \ +- } \ +-} +- +-VCMPI(vseqi_b, 8, B, VSEQ) +-VCMPI(vseqi_h, 16, H, VSEQ) +-VCMPI(vseqi_w, 32, W, VSEQ) +-VCMPI(vseqi_d, 64, D, VSEQ) +-VCMPI(vslei_b, 8, B, VSLE) +-VCMPI(vslei_h, 16, H, VSLE) +-VCMPI(vslei_w, 32, W, VSLE) +-VCMPI(vslei_d, 64, D, VSLE) +-VCMPI(vslei_bu, 8, UB, VSLE) +-VCMPI(vslei_hu, 16, UH, VSLE) +-VCMPI(vslei_wu, 32, UW, VSLE) +-VCMPI(vslei_du, 64, UD, VSLE) +-VCMPI(vslti_b, 8, B, VSLT) +-VCMPI(vslti_h, 16, H, VSLT) +-VCMPI(vslti_w, 32, W, VSLT) +-VCMPI(vslti_d, 64, D, VSLT) +-VCMPI(vslti_bu, 8, UB, VSLT) +-VCMPI(vslti_hu, 16, UH, VSLT) +-VCMPI(vslti_wu, 32, UW, VSLT) +-VCMPI(vslti_du, 64, UD, VSLT) +- +-static uint64_t vfcmp_common(CPULoongArchState *env, +- FloatRelation cmp, uint32_t flags) +-{ +- uint64_t ret = 0; +- +- switch (cmp) { +- case float_relation_less: +- ret = (flags & FCMP_LT); +- break; +- case float_relation_equal: +- ret = (flags & FCMP_EQ); +- break; +- case float_relation_greater: +- ret = (flags & FCMP_GT); +- break; +- case float_relation_unordered: +- ret = (flags & FCMP_UN); +- break; +- default: +- g_assert_not_reached(); +- } +- +- if (ret) { +- ret = -1; +- } +- +- return ret; +-} +- +-#define VFCMP(NAME, BIT, E, FN) \ +-void HELPER(NAME)(CPULoongArchState *env, uint32_t oprsz, \ +- uint32_t vd, uint32_t vj, uint32_t vk, uint32_t flags) \ +-{ \ +- int i; \ +- VReg t; \ +- VReg *Vd = &(env->fpr[vd].vreg); \ +- VReg *Vj = &(env->fpr[vj].vreg); \ +- VReg *Vk = &(env->fpr[vk].vreg); \ +- \ +- vec_clear_cause(env); \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- FloatRelation cmp; \ +- cmp = FN(Vj->E(i), Vk->E(i), &env->fp_status); \ +- t.E(i) = vfcmp_common(env, cmp, flags); \ +- vec_update_fcsr0(env, GETPC()); \ +- } \ +- *Vd = t; \ +-} +- +-VFCMP(vfcmp_c_s, 32, UW, float32_compare_quiet) +-VFCMP(vfcmp_s_s, 32, UW, float32_compare) +-VFCMP(vfcmp_c_d, 64, UD, float64_compare_quiet) +-VFCMP(vfcmp_s_d, 64, UD, float64_compare) +- +-void HELPER(vbitseli_b)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- +- for (i = 0; i < simd_oprsz(desc); i++) { +- Vd->B(i) = (~Vd->B(i) & Vj->B(i)) | (Vd->B(i) & imm); +- } +-} +- +-/* Copy from target/arm/tcg/sve_helper.c */ +-static inline bool do_match2(uint64_t n, uint64_t m0, uint64_t m1, int esz) +-{ +- int bits = 8 << esz; +- uint64_t ones = dup_const(esz, 1); +- uint64_t signs = ones << (bits - 1); +- uint64_t cmp0, cmp1; +- +- cmp1 = dup_const(esz, n); +- cmp0 = cmp1 ^ m0; +- cmp1 = cmp1 ^ m1; +- cmp0 = (cmp0 - ones) & ~cmp0; +- cmp1 = (cmp1 - ones) & ~cmp1; +- return (cmp0 | cmp1) & signs; +-} +- +-#define SETANYEQZ(NAME, MO) \ +-void HELPER(NAME)(CPULoongArchState *env, \ +- uint32_t oprsz, uint32_t cd, uint32_t vj) \ +-{ \ +- VReg *Vj = &(env->fpr[vj].vreg); \ +- \ +- env->cf[cd & 0x7] = do_match2(0, Vj->D(0), Vj->D(1), MO); \ +- if (oprsz == 32) { \ +- env->cf[cd & 0x7] = env->cf[cd & 0x7] || \ +- do_match2(0, Vj->D(2), Vj->D(3), MO); \ +- } \ +-} +- +-SETANYEQZ(vsetanyeqz_b, MO_8) +-SETANYEQZ(vsetanyeqz_h, MO_16) +-SETANYEQZ(vsetanyeqz_w, MO_32) +-SETANYEQZ(vsetanyeqz_d, MO_64) +- +-#define SETALLNEZ(NAME, MO) \ +-void HELPER(NAME)(CPULoongArchState *env, \ +- uint32_t oprsz, uint32_t cd, uint32_t vj) \ +-{ \ +- VReg *Vj = &(env->fpr[vj].vreg); \ +- \ +- env->cf[cd & 0x7]= !do_match2(0, Vj->D(0), Vj->D(1), MO); \ +- if (oprsz == 32) { \ +- env->cf[cd & 0x7] = env->cf[cd & 0x7] && \ +- !do_match2(0, Vj->D(2), Vj->D(3), MO); \ +- } \ +-} +- +-SETALLNEZ(vsetallnez_b, MO_8) +-SETALLNEZ(vsetallnez_h, MO_16) +-SETALLNEZ(vsetallnez_w, MO_32) +-SETALLNEZ(vsetallnez_d, MO_64) +- +-#define XVINSVE0(NAME, E, MASK) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- Vd->E(imm & MASK) = Vj->E(0); \ +-} +- +-XVINSVE0(xvinsve0_w, W, 0x7) +-XVINSVE0(xvinsve0_d, D, 0x3) +- +-#define XVPICKVE(NAME, E, BIT, MASK) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- Vd->E(0) = Vj->E(imm & MASK); \ +- for (i = 1; i < oprsz / (BIT / 8); i++) { \ +- Vd->E(i) = 0; \ +- } \ +-} +- +-XVPICKVE(xvpickve_w, W, 32, 0x7) +-XVPICKVE(xvpickve_d, D, 64, 0x3) +- +-#define VPACKEV(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- temp.E(2 * i + 1) = Vj->E(2 * i); \ +- temp.E(2 *i) = Vk->E(2 * i); \ +- } \ +- *Vd = temp; \ +-} +- +-VPACKEV(vpackev_b, 16, B) +-VPACKEV(vpackev_h, 32, H) +-VPACKEV(vpackev_w, 64, W) +-VPACKEV(vpackev_d, 128, D) +- +-#define VPACKOD(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- temp.E(2 * i + 1) = Vj->E(2 * i + 1); \ +- temp.E(2 * i) = Vk->E(2 * i + 1); \ +- } \ +- *Vd = temp; \ +-} +- +-VPACKOD(vpackod_b, 16, B) +-VPACKOD(vpackod_h, 32, H) +-VPACKOD(vpackod_w, 64, W) +-VPACKOD(vpackod_d, 128, D) +- +-#define VPICKEV(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E(j + ofs * (2 * i + 1)) = Vj->E(2 * (j + ofs * i)); \ +- temp.E(j + ofs * 2 * i) = Vk->E(2 * (j + ofs * i)); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-VPICKEV(vpickev_b, 16, B) +-VPICKEV(vpickev_h, 32, H) +-VPICKEV(vpickev_w, 64, W) +-VPICKEV(vpickev_d, 128, D) +- +-#define VPICKOD(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E(j + ofs * (2 * i + 1)) = Vj->E(2 * (j + ofs * i) + 1); \ +- temp.E(j + ofs * 2 * i) = Vk->E(2 * (j + ofs * i) + 1); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-VPICKOD(vpickod_b, 16, B) +-VPICKOD(vpickod_h, 32, H) +-VPICKOD(vpickod_w, 64, W) +-VPICKOD(vpickod_d, 128, D) +- +-#define VILVL(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E(2 * (j + ofs * i) + 1) = Vj->E(j + ofs * 2 * i); \ +- temp.E(2 * (j + ofs * i)) = Vk->E(j + ofs * 2 * i); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-VILVL(vilvl_b, 16, B) +-VILVL(vilvl_h, 32, H) +-VILVL(vilvl_w, 64, W) +-VILVL(vilvl_d, 128, D) +- +-#define VILVH(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, ofs; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- ofs = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- for (j = 0; j < ofs; j++) { \ +- temp.E(2 * (j + ofs * i) + 1) = Vj->E(j + ofs * (2 * i + 1)); \ +- temp.E(2 * (j + ofs * i)) = Vk->E(j + ofs * (2 * i + 1)); \ +- } \ +- } \ +- *Vd = temp; \ +-} +- +-VILVH(vilvh_b, 16, B) +-VILVH(vilvh_h, 32, H) +-VILVH(vilvh_w, 64, W) +-VILVH(vilvh_d, 128, D) +- +-void HELPER(vshuf_b)(void *vd, void *vj, void *vk, void *va, uint32_t desc) +-{ +- int i, j, m; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- VReg *Va = (VReg *)va; +- int oprsz = simd_oprsz(desc); +- +- m = LSX_LEN / 8; +- for (i = 0; i < (oprsz / 16) * m; i++) { +- j = i < m ? 0 : 1; +- uint64_t k = (uint8_t)Va->B(i) % (2 * m); +- temp.B(i) = k < m ? Vk->B(k + j * m): Vj->B(k + (j - 1) * m); +- } +- *Vd = temp; +-} +- +-#define VSHUF(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, void *vk, uint32_t desc) \ +-{ \ +- int i, j, m; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- VReg *Vk = (VReg *)vk; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- m = LSX_LEN / BIT; \ +- for (i = 0; i < (oprsz / 16) * m; i++) { \ +- j = i < m ? 0 : 1; \ +- uint64_t k = ((uint8_t)Vd->E(i)) % (2 * m); \ +- temp.E(i) = k < m ? Vk->E(k + j * m) : Vj->E(k + (j - 1) * m); \ +- } \ +- *Vd = temp; \ +-} +- +-VSHUF(vshuf_h, 16, H) +-VSHUF(vshuf_w, 32, W) +-VSHUF(vshuf_d, 64, D) +- +-#define VSHUF4I(NAME, BIT, E) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, j, max; \ +- VReg temp = {}; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- max = LSX_LEN / BIT; \ +- for (i = 0; i < oprsz / (BIT / 8); i++) { \ +- j = i < max ? 1 : 2; \ +- temp.E(i) = Vj->E(SHF_POS(i - ((j -1)* max), imm) + (j - 1) * max); \ +- } \ +- *Vd = temp; \ +-} +- +-VSHUF4I(vshuf4i_b, 8, B) +-VSHUF4I(vshuf4i_h, 16, H) +-VSHUF4I(vshuf4i_w, 32, W) +- +-void HELPER(vshuf4i_d)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- temp.D(2 * i) = (imm & 2 ? Vj : Vd)->D((imm & 1) + 2 * i); +- temp.D(2 * i + 1) = (imm & 8 ? Vj : Vd)->D(((imm >> 2) & 1) + 2 * i); +- } +- *Vd = temp; +-} +- +-void HELPER(vperm_w)(void *vd, void *vj, void *vk, uint32_t desc) +-{ +- int i, m; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- VReg *Vk = (VReg *)vk; +- +- m = LASX_LEN / 32; +- for (i = 0; i < m ; i++) { +- uint64_t k = (uint8_t)Vk->W(i) % 8; +- temp.W(i) = Vj->W(k); +- } +- *Vd = temp; +-} +- +-void HELPER(vpermi_w)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- int oprsz = simd_oprsz(desc); +- +- for (i = 0; i < oprsz / 16; i++) { +- temp.W(4 * i) = Vj->W((imm & 0x3) + 4 * i); +- temp.W(4 * i + 1) = Vj->W(((imm >> 2) & 0x3) + 4 * i); +- temp.W(4 * i + 2) = Vd->W(((imm >> 4) & 0x3) + 4 * i); +- temp.W(4 * i + 3) = Vd->W(((imm >> 6) & 0x3) + 4 * i); +- } +- *Vd = temp; +-} +- +-void HELPER(vpermi_d)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- VReg temp = {}; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- +- temp.D(0) = Vj->D(imm & 0x3); +- temp.D(1) = Vj->D((imm >> 2) & 0x3); +- temp.D(2) = Vj->D((imm >> 4) & 0x3); +- temp.D(3) = Vj->D((imm >> 6) & 0x3); +- *Vd = temp; +-} +- +-void HELPER(vpermi_q)(void *vd, void *vj, uint64_t imm, uint32_t desc) +-{ +- int i; +- VReg temp; +- VReg *Vd = (VReg *)vd; +- VReg *Vj = (VReg *)vj; +- +- for (i = 0; i < 2; i++, imm >>= 4) { +- temp.Q(i) = (imm & 2 ? Vd: Vj)->Q(imm & 1); +- } +- *Vd = temp; +-} +- +-#define VEXTRINS(NAME, BIT, E, MASK) \ +-void HELPER(NAME)(void *vd, void *vj, uint64_t imm, uint32_t desc) \ +-{ \ +- int i, ins, extr, max; \ +- VReg *Vd = (VReg *)vd; \ +- VReg *Vj = (VReg *)vj; \ +- int oprsz = simd_oprsz(desc); \ +- \ +- max = LSX_LEN / BIT; \ +- ins = (imm >> 4) & MASK; \ +- extr = imm & MASK; \ +- for (i = 0; i < oprsz / 16; i++) { \ +- Vd->E(ins + i * max) = Vj->E(extr + i * max); \ +- } \ +-} +- +-VEXTRINS(vextrins_b, 8, B, 0xf) +-VEXTRINS(vextrins_h, 16, H, 0x7) +-VEXTRINS(vextrins_w, 32, W, 0x3) +-VEXTRINS(vextrins_d, 64, D, 0x1) +-- +1.8.3.1 + diff --git a/0007-linux-headers-Update-to-Linux-v6.7-rc5.patch b/0152-linux-headers-Update-to-Linux-v6.7-rc5.patch similarity index 92% rename from 0007-linux-headers-Update-to-Linux-v6.7-rc5.patch rename to 0152-linux-headers-Update-to-Linux-v6.7-rc5.patch index 44129bda8915ee338b6bfca0cb291f9c40f8f837..fbed22766e509dcabf0a9b0a7f330dd70cf39911 100644 --- a/0007-linux-headers-Update-to-Linux-v6.7-rc5.patch +++ b/0152-linux-headers-Update-to-Linux-v6.7-rc5.patch @@ -1,7 +1,7 @@ -From 9904eb7d4559baca2da713346cd505a80af7e776 Mon Sep 17 00:00:00 2001 +From bbc1dee97b5a31586e87824abfc84d911ed97d4f Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 17:43:18 -0300 -Subject: [PATCH] linux-headers: Update to Linux v6.7-rc5 +Subject: [PATCH 162/293] linux-headers: Update to Linux v6.7-rc5 We'll add a new RISC-V linux-header file, but first let's update all headers. @@ -13,35 +13,35 @@ Acked-by: Alistair Francis Message-ID: <20231218204321.75757-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- - include/standard-headers/drm/drm_fourcc.h | 2 + - include/standard-headers/linux/pci_regs.h | 24 ++- - include/standard-headers/linux/vhost_types.h | 7 + - .../standard-headers/linux/virtio_config.h | 5 + - include/standard-headers/linux/virtio_pci.h | 11 ++ - linux-headers/asm-arm64/kvm.h | 32 ++++ - linux-headers/asm-generic/unistd.h | 14 +- - linux-headers/asm-loongarch/bitsperlong.h | 1 + - linux-headers/asm-loongarch/kvm.h | 108 +++++++++++ - linux-headers/asm-loongarch/mman.h | 1 + - linux-headers/asm-loongarch/unistd.h | 5 + - linux-headers/asm-mips/unistd_n32.h | 4 + - linux-headers/asm-mips/unistd_n64.h | 4 + - linux-headers/asm-mips/unistd_o32.h | 4 + - linux-headers/asm-powerpc/unistd_32.h | 4 + - linux-headers/asm-powerpc/unistd_64.h | 4 + - linux-headers/asm-riscv/kvm.h | 12 ++ - linux-headers/asm-s390/unistd_32.h | 4 + - linux-headers/asm-s390/unistd_64.h | 4 + - linux-headers/asm-x86/unistd_32.h | 4 + - linux-headers/asm-x86/unistd_64.h | 3 + - linux-headers/asm-x86/unistd_x32.h | 3 + - linux-headers/linux/iommufd.h | 180 +++++++++++++++++- - linux-headers/linux/kvm.h | 11 ++ - linux-headers/linux/psp-sev.h | 1 + - linux-headers/linux/stddef.h | 9 +- - linux-headers/linux/userfaultfd.h | 9 +- - linux-headers/linux/vfio.h | 47 +++-- - linux-headers/linux/vhost.h | 8 + + include/standard-headers/drm/drm_fourcc.h | 2 + + include/standard-headers/linux/pci_regs.h | 24 +++- + include/standard-headers/linux/vhost_types.h | 7 + + include/standard-headers/linux/virtio_config.h | 5 + + include/standard-headers/linux/virtio_pci.h | 11 ++ + linux-headers/asm-arm64/kvm.h | 32 +++++ + linux-headers/asm-generic/unistd.h | 14 +- + linux-headers/asm-loongarch/bitsperlong.h | 1 + + linux-headers/asm-loongarch/kvm.h | 108 +++++++++++++++ + linux-headers/asm-loongarch/mman.h | 1 + + linux-headers/asm-loongarch/unistd.h | 5 + + linux-headers/asm-mips/unistd_n32.h | 4 + + linux-headers/asm-mips/unistd_n64.h | 4 + + linux-headers/asm-mips/unistd_o32.h | 4 + + linux-headers/asm-powerpc/unistd_32.h | 4 + + linux-headers/asm-powerpc/unistd_64.h | 4 + + linux-headers/asm-riscv/kvm.h | 12 ++ + linux-headers/asm-s390/unistd_32.h | 4 + + linux-headers/asm-s390/unistd_64.h | 4 + + linux-headers/asm-x86/unistd_32.h | 4 + + linux-headers/asm-x86/unistd_64.h | 3 + + linux-headers/asm-x86/unistd_x32.h | 3 + + linux-headers/linux/iommufd.h | 180 ++++++++++++++++++++++++- + linux-headers/linux/kvm.h | 11 ++ + linux-headers/linux/psp-sev.h | 1 + + linux-headers/linux/stddef.h | 9 +- + linux-headers/linux/userfaultfd.h | 9 +- + linux-headers/linux/vfio.h | 47 +++++-- + linux-headers/linux/vhost.h | 8 ++ 29 files changed, 498 insertions(+), 27 deletions(-) create mode 100644 linux-headers/asm-loongarch/bitsperlong.h create mode 100644 linux-headers/asm-loongarch/kvm.h @@ -49,7 +49,7 @@ Signed-off-by: Alistair Francis create mode 100644 linux-headers/asm-loongarch/unistd.h diff --git a/include/standard-headers/drm/drm_fourcc.h b/include/standard-headers/drm/drm_fourcc.h -index 72279f4d25..3afb70160f 100644 +index 72279f4..3afb701 100644 --- a/include/standard-headers/drm/drm_fourcc.h +++ b/include/standard-headers/drm/drm_fourcc.h @@ -322,6 +322,8 @@ extern "C" { @@ -62,7 +62,7 @@ index 72279f4d25..3afb70160f 100644 /* * 2 plane YCbCr MSB aligned diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h -index e5f558d964..a39193213f 100644 +index e5f558d..a391932 100644 --- a/include/standard-headers/linux/pci_regs.h +++ b/include/standard-headers/linux/pci_regs.h @@ -80,6 +80,7 @@ @@ -136,7 +136,7 @@ index e5f558d964..a39193213f 100644 /* Designated Vendor-Specific (DVSEC, PCI_EXT_CAP_ID_DVSEC) */ #define PCI_DVSEC_HEADER1 0x4 /* Designated Vendor-Specific Header1 */ diff --git a/include/standard-headers/linux/vhost_types.h b/include/standard-headers/linux/vhost_types.h -index 5ad07e134a..fd54044936 100644 +index 5ad07e1..fd54044 100644 --- a/include/standard-headers/linux/vhost_types.h +++ b/include/standard-headers/linux/vhost_types.h @@ -185,5 +185,12 @@ struct vhost_vdpa_iova_range { @@ -153,7 +153,7 @@ index 5ad07e134a..fd54044936 100644 #endif diff --git a/include/standard-headers/linux/virtio_config.h b/include/standard-headers/linux/virtio_config.h -index 8a7d0dc8b0..bfd1ca643e 100644 +index 8a7d0dc..bfd1ca6 100644 --- a/include/standard-headers/linux/virtio_config.h +++ b/include/standard-headers/linux/virtio_config.h @@ -103,6 +103,11 @@ @@ -169,7 +169,7 @@ index 8a7d0dc8b0..bfd1ca643e 100644 * This feature indicates that the driver can reset a queue individually. */ diff --git a/include/standard-headers/linux/virtio_pci.h b/include/standard-headers/linux/virtio_pci.h -index be912cfc95..b7fdfd0668 100644 +index be912cf..b7fdfd0 100644 --- a/include/standard-headers/linux/virtio_pci.h +++ b/include/standard-headers/linux/virtio_pci.h @@ -166,6 +166,17 @@ struct virtio_pci_common_cfg { @@ -191,7 +191,7 @@ index be912cfc95..b7fdfd0668 100644 struct virtio_pci_cfg_cap { struct virtio_pci_cap cap; diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h -index 38e5957526..c59ea55cd8 100644 +index 38e5957..c59ea55 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -491,6 +491,38 @@ struct kvm_smccc_filter { @@ -234,7 +234,7 @@ index 38e5957526..c59ea55cd8 100644 #endif /* __ARM_KVM_H__ */ diff --git a/linux-headers/asm-generic/unistd.h b/linux-headers/asm-generic/unistd.h -index abe087c53b..756b013fb8 100644 +index abe087c..756b013 100644 --- a/linux-headers/asm-generic/unistd.h +++ b/linux-headers/asm-generic/unistd.h @@ -71,7 +71,7 @@ __SYSCALL(__NR_fremovexattr, sys_fremovexattr) @@ -273,14 +273,14 @@ index abe087c53b..756b013fb8 100644 * 32 bit systems traditionally used different diff --git a/linux-headers/asm-loongarch/bitsperlong.h b/linux-headers/asm-loongarch/bitsperlong.h new file mode 100644 -index 0000000000..6dc0bb0c13 +index 0000000..6dc0bb0 --- /dev/null +++ b/linux-headers/asm-loongarch/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h new file mode 100644 -index 0000000000..c6ad2ee610 +index 0000000..c6ad2ee --- /dev/null +++ b/linux-headers/asm-loongarch/kvm.h @@ -0,0 +1,108 @@ @@ -394,14 +394,14 @@ index 0000000000..c6ad2ee610 +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */ diff --git a/linux-headers/asm-loongarch/mman.h b/linux-headers/asm-loongarch/mman.h new file mode 100644 -index 0000000000..8eebf89f5a +index 0000000..8eebf89 --- /dev/null +++ b/linux-headers/asm-loongarch/mman.h @@ -0,0 +1 @@ +#include diff --git a/linux-headers/asm-loongarch/unistd.h b/linux-headers/asm-loongarch/unistd.h new file mode 100644 -index 0000000000..fcb668984f +index 0000000..fcb6689 --- /dev/null +++ b/linux-headers/asm-loongarch/unistd.h @@ -0,0 +1,5 @@ @@ -411,7 +411,7 @@ index 0000000000..fcb668984f + +#include diff --git a/linux-headers/asm-mips/unistd_n32.h b/linux-headers/asm-mips/unistd_n32.h -index 46d8500654..994b6f008f 100644 +index 46d8500..994b6f0 100644 --- a/linux-headers/asm-mips/unistd_n32.h +++ b/linux-headers/asm-mips/unistd_n32.h @@ -381,5 +381,9 @@ @@ -425,7 +425,7 @@ index 46d8500654..994b6f008f 100644 #endif /* _ASM_UNISTD_N32_H */ diff --git a/linux-headers/asm-mips/unistd_n64.h b/linux-headers/asm-mips/unistd_n64.h -index c2f7ac673b..41dcf5877a 100644 +index c2f7ac6..41dcf58 100644 --- a/linux-headers/asm-mips/unistd_n64.h +++ b/linux-headers/asm-mips/unistd_n64.h @@ -357,5 +357,9 @@ @@ -439,7 +439,7 @@ index c2f7ac673b..41dcf5877a 100644 #endif /* _ASM_UNISTD_N64_H */ diff --git a/linux-headers/asm-mips/unistd_o32.h b/linux-headers/asm-mips/unistd_o32.h -index 757c68f2ad..ae9d334d96 100644 +index 757c68f..ae9d334 100644 --- a/linux-headers/asm-mips/unistd_o32.h +++ b/linux-headers/asm-mips/unistd_o32.h @@ -427,5 +427,9 @@ @@ -453,7 +453,7 @@ index 757c68f2ad..ae9d334d96 100644 #endif /* _ASM_UNISTD_O32_H */ diff --git a/linux-headers/asm-powerpc/unistd_32.h b/linux-headers/asm-powerpc/unistd_32.h -index 8ef94bbac1..b9b23d66d7 100644 +index 8ef94bb..b9b23d6 100644 --- a/linux-headers/asm-powerpc/unistd_32.h +++ b/linux-headers/asm-powerpc/unistd_32.h @@ -434,6 +434,10 @@ @@ -468,7 +468,7 @@ index 8ef94bbac1..b9b23d66d7 100644 #endif /* _ASM_UNISTD_32_H */ diff --git a/linux-headers/asm-powerpc/unistd_64.h b/linux-headers/asm-powerpc/unistd_64.h -index 0e7ee43e88..cbb4b3e8f7 100644 +index 0e7ee43..cbb4b3e 100644 --- a/linux-headers/asm-powerpc/unistd_64.h +++ b/linux-headers/asm-powerpc/unistd_64.h @@ -406,6 +406,10 @@ @@ -483,7 +483,7 @@ index 0e7ee43e88..cbb4b3e8f7 100644 #endif /* _ASM_UNISTD_64_H */ diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h -index 992c5e4071..60d3b21dea 100644 +index 992c5e4..60d3b21 100644 --- a/linux-headers/asm-riscv/kvm.h +++ b/linux-headers/asm-riscv/kvm.h @@ -80,6 +80,7 @@ struct kvm_riscv_csr { @@ -538,7 +538,7 @@ index 992c5e4071..60d3b21dea 100644 /* Timer registers are mapped as type 4 */ #define KVM_REG_RISCV_TIMER (0x04 << KVM_REG_RISCV_TYPE_SHIFT) diff --git a/linux-headers/asm-s390/unistd_32.h b/linux-headers/asm-s390/unistd_32.h -index 716fa368ca..c093e6d5f9 100644 +index 716fa36..c093e6d 100644 --- a/linux-headers/asm-s390/unistd_32.h +++ b/linux-headers/asm-s390/unistd_32.h @@ -425,5 +425,9 @@ @@ -552,7 +552,7 @@ index 716fa368ca..c093e6d5f9 100644 #endif /* _ASM_S390_UNISTD_32_H */ diff --git a/linux-headers/asm-s390/unistd_64.h b/linux-headers/asm-s390/unistd_64.h -index b2a11b1d13..114c0569a4 100644 +index b2a11b1..114c056 100644 --- a/linux-headers/asm-s390/unistd_64.h +++ b/linux-headers/asm-s390/unistd_64.h @@ -373,5 +373,9 @@ @@ -566,7 +566,7 @@ index b2a11b1d13..114c0569a4 100644 #endif /* _ASM_S390_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/unistd_32.h b/linux-headers/asm-x86/unistd_32.h -index d749ad1c24..329649c377 100644 +index d749ad1..329649c 100644 --- a/linux-headers/asm-x86/unistd_32.h +++ b/linux-headers/asm-x86/unistd_32.h @@ -443,6 +443,10 @@ @@ -581,7 +581,7 @@ index d749ad1c24..329649c377 100644 #endif /* _ASM_UNISTD_32_H */ diff --git a/linux-headers/asm-x86/unistd_64.h b/linux-headers/asm-x86/unistd_64.h -index cea67282eb..4583606ce6 100644 +index cea6728..4583606 100644 --- a/linux-headers/asm-x86/unistd_64.h +++ b/linux-headers/asm-x86/unistd_64.h @@ -366,6 +366,9 @@ @@ -595,7 +595,7 @@ index cea67282eb..4583606ce6 100644 #endif /* _ASM_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h -index 5b2e79bf4c..146d74d8e4 100644 +index 5b2e79b..146d74d 100644 --- a/linux-headers/asm-x86/unistd_x32.h +++ b/linux-headers/asm-x86/unistd_x32.h @@ -318,6 +318,9 @@ @@ -609,7 +609,7 @@ index 5b2e79bf4c..146d74d8e4 100644 #define __NR_rt_sigreturn (__X32_SYSCALL_BIT + 513) #define __NR_ioctl (__X32_SYSCALL_BIT + 514) diff --git a/linux-headers/linux/iommufd.h b/linux-headers/linux/iommufd.h -index 218bf7ac98..806d98d09c 100644 +index 218bf7a..806d98d 100644 --- a/linux-headers/linux/iommufd.h +++ b/linux-headers/linux/iommufd.h @@ -47,6 +47,8 @@ enum { @@ -621,11 +621,10 @@ index 218bf7ac98..806d98d09c 100644 }; /** -@@ -347,20 +349,86 @@ struct iommu_vfio_ioas { - }; +@@ -348,19 +350,85 @@ struct iommu_vfio_ioas { #define IOMMU_VFIO_IOAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VFIO_IOAS) -+/** + /** + * enum iommufd_hwpt_alloc_flags - Flags for HWPT allocation + * @IOMMU_HWPT_ALLOC_NEST_PARENT: If set, allocate a HWPT that can serve as + * the parent HWPT in a nesting configuration. @@ -675,7 +674,7 @@ index 218bf7ac98..806d98d09c 100644 + IOMMU_HWPT_DATA_VTD_S1, +}; + - /** ++/** * struct iommu_hwpt_alloc - ioctl(IOMMU_HWPT_ALLOC) * @size: sizeof(struct iommu_hwpt_alloc) - * @flags: Must be 0 @@ -721,7 +720,7 @@ index 218bf7ac98..806d98d09c 100644 }; #define IOMMU_HWPT_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_ALLOC) -+/** + /** + * enum iommu_hw_info_vtd_flags - Flags for VT-d hw_info + * @IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17: If set, disallow read-only mappings + * on a nested_parent domain. @@ -731,7 +730,7 @@ index 218bf7ac98..806d98d09c 100644 + IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17 = 1 << 0, +}; + - /** ++/** * struct iommu_hw_info_vtd - Intel VT-d hardware information * - * @flags: Must be 0 @@ -739,11 +738,10 @@ index 218bf7ac98..806d98d09c 100644 * @__reserved: Must be 0 * * @cap_reg: Value of Intel VT-d capability register defined in VT-d spec -@@ -404,6 +485,20 @@ enum iommu_hw_info_type { - IOMMU_HW_INFO_TYPE_INTEL_VTD, +@@ -405,6 +486,20 @@ enum iommu_hw_info_type { }; -+/** + /** + * enum iommufd_hw_capabilities + * @IOMMU_HW_CAP_DIRTY_TRACKING: IOMMU hardware support for dirty tracking + * If available, it means the following APIs @@ -757,9 +755,10 @@ index 218bf7ac98..806d98d09c 100644 + IOMMU_HW_CAP_DIRTY_TRACKING = 1 << 0, +}; + - /** ++/** * struct iommu_hw_info - ioctl(IOMMU_GET_HW_INFO) * @size: sizeof(struct iommu_hw_info) + * @flags: Must be 0 @@ -415,6 +510,8 @@ enum iommu_hw_info_type { * the iommu type specific hardware information data * @out_data_type: Output the iommu hardware info type as defined in the enum @@ -852,7 +851,7 @@ index 218bf7ac98..806d98d09c 100644 + #endif diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 0d74ee999a..549fea3a97 100644 +index 0d74ee9..549fea3 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -264,6 +264,7 @@ struct kvm_xen_exit { @@ -902,7 +901,7 @@ index 0d74ee999a..549fea3a97 100644 /* ioctl for vm fd */ #define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device) diff --git a/linux-headers/linux/psp-sev.h b/linux-headers/linux/psp-sev.h -index 12ccb70099..bcb21339ee 100644 +index 12ccb70..bcb2133 100644 --- a/linux-headers/linux/psp-sev.h +++ b/linux-headers/linux/psp-sev.h @@ -68,6 +68,7 @@ typedef enum { @@ -914,7 +913,7 @@ index 12ccb70099..bcb21339ee 100644 } sev_ret_code; diff --git a/linux-headers/linux/stddef.h b/linux-headers/linux/stddef.h -index 9bb07083ac..bf9749dd14 100644 +index 9bb0708..bf9749d 100644 --- a/linux-headers/linux/stddef.h +++ b/linux-headers/linux/stddef.h @@ -27,8 +27,13 @@ @@ -939,7 +938,7 @@ index 9bb07083ac..bf9749dd14 100644 + +#endif /* _LINUX_STDDEF_H */ diff --git a/linux-headers/linux/userfaultfd.h b/linux-headers/linux/userfaultfd.h -index 59978fbaae..953c75feda 100644 +index 59978fb..953c75f 100644 --- a/linux-headers/linux/userfaultfd.h +++ b/linux-headers/linux/userfaultfd.h @@ -40,7 +40,8 @@ @@ -973,7 +972,7 @@ index 59978fbaae..953c75feda 100644 __u64 ioctls; diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h -index acf72b4999..8e175ece31 100644 +index acf72b4..8e175ece3 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -277,8 +277,8 @@ struct vfio_region_info { @@ -1088,7 +1087,7 @@ index acf72b4999..8e175ece31 100644 __u32 pad; }; diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h -index f5c48b61ab..649560c685 100644 +index f5c48b6..649560c 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -219,4 +219,12 @@ @@ -1105,5 +1104,5 @@ index f5c48b61ab..649560c685 100644 + struct vhost_vring_state) #endif -- -2.33.0 +1.8.3.1 diff --git a/0008-linux-headers-Synchronize-linux-headers-from-linux-v.patch b/0153-linux-headers-Synchronize-linux-headers-from-linux-v.patch similarity index 91% rename from 0008-linux-headers-Synchronize-linux-headers-from-linux-v.patch rename to 0153-linux-headers-Synchronize-linux-headers-from-linux-v.patch index cf5110889808e1226f10387fbf5a6642098eb1bc..2e00665bf0f7e3afef08656e3c0a1c52b50bf34d 100644 --- a/0008-linux-headers-Synchronize-linux-headers-from-linux-v.patch +++ b/0153-linux-headers-Synchronize-linux-headers-from-linux-v.patch @@ -1,7 +1,7 @@ -From 280cba84e3eaed10f095f0c88dab27b7799558e5 Mon Sep 17 00:00:00 2001 +From 9a9f7dc1d32aae12505088b1ab7d2986d947ac30 Mon Sep 17 00:00:00 2001 From: Tianrui Zhao Date: Fri, 5 Jan 2024 15:57:56 +0800 -Subject: [PATCH] linux-headers: Synchronize linux headers from linux +Subject: [PATCH 163/293] linux-headers: Synchronize linux headers from linux v6.7.0-rc8 Use the scripts/update-linux-headers.sh to synchronize linux @@ -18,7 +18,7 @@ Signed-off-by: Song Gao 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/standard-headers/linux/fuse.h b/include/standard-headers/linux/fuse.h -index 6b9793842c..fc0dcd10ae 100644 +index 6b97938..fc0dcd1 100644 --- a/include/standard-headers/linux/fuse.h +++ b/include/standard-headers/linux/fuse.h @@ -209,7 +209,7 @@ @@ -53,5 +53,5 @@ index 6b9793842c..fc0dcd10ae 100644 /** * CUSE INIT request/reply flags -- -2.33.0 +1.8.3.1 diff --git a/0009-target-loongarch-Define-some-kvm_arch-interfaces.patch b/0154-target-loongarch-Define-some-kvm_arch-interfaces.patch similarity index 94% rename from 0009-target-loongarch-Define-some-kvm_arch-interfaces.patch rename to 0154-target-loongarch-Define-some-kvm_arch-interfaces.patch index 5e6dcc55644f210018eb9e69fe4b57ffec273b93..b9633230108ddd8885abaa6e2c9c2c710245e7a5 100644 --- a/0009-target-loongarch-Define-some-kvm_arch-interfaces.patch +++ b/0154-target-loongarch-Define-some-kvm_arch-interfaces.patch @@ -1,7 +1,7 @@ -From 623a99084843f47723cb799d4bcef8e1359d59ad Mon Sep 17 00:00:00 2001 +From 6295d46c364084e3a733d04e24840daa407cbab5 Mon Sep 17 00:00:00 2001 From: Tianrui Zhao Date: Fri, 5 Jan 2024 15:57:57 +0800 -Subject: [PATCH] target/loongarch: Define some kvm_arch interfaces +Subject: [PATCH 164/293] target/loongarch: Define some kvm_arch interfaces Define some functions in target/loongarch/kvm/kvm.c, such as kvm_arch_put_registers, kvm_arch_get_registers @@ -16,13 +16,13 @@ Reviewed-by: Song Gao Message-Id: <20240105075804.1228596-3-zhaotianrui@loongson.cn> Signed-off-by: Song Gao --- - target/loongarch/kvm/kvm.c | 131 +++++++++++++++++++++++++++++++++++++ + target/loongarch/kvm/kvm.c | 131 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 target/loongarch/kvm/kvm.c diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c new file mode 100644 -index 0000000000..0d67322fd9 +index 0000000..0d67322 --- /dev/null +++ b/target/loongarch/kvm/kvm.c @@ -0,0 +1,131 @@ @@ -158,5 +158,5 @@ index 0000000000..0d67322fd9 +{ +} -- -2.33.0 +1.8.3.1 diff --git a/0010-target-loongarch-Supplement-vcpu-env-initial-when-vc.patch b/0155-target-loongarch-Supplement-vcpu-env-initial-when-vc.patch similarity index 90% rename from 0010-target-loongarch-Supplement-vcpu-env-initial-when-vc.patch rename to 0155-target-loongarch-Supplement-vcpu-env-initial-when-vc.patch index 4ef4a96ff09cec2b926f798c5b76a14907950ff3..23334491a84288be6ec0972d6a8b88166aee0809 100644 --- a/0010-target-loongarch-Supplement-vcpu-env-initial-when-vc.patch +++ b/0155-target-loongarch-Supplement-vcpu-env-initial-when-vc.patch @@ -1,8 +1,8 @@ -From 48dae5f461bf2cde206e879d52df6cf1bad3ac6e Mon Sep 17 00:00:00 2001 +From ecca5952a131a81d0e0453a532c086df9d0df92d Mon Sep 17 00:00:00 2001 From: Tianrui Zhao Date: Fri, 5 Jan 2024 15:57:58 +0800 -Subject: [PATCH] target/loongarch: Supplement vcpu env initial when vcpu - reset +Subject: [PATCH 165/293] target/loongarch: Supplement vcpu env initial when + vcpu reset Supplement vcpu env initial when vcpu reset, including init vcpu CSR_CPUID,CSR_TID to cpu->cpu_index. The two @@ -19,7 +19,7 @@ Signed-off-by: Song Gao 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c -index db9a421cc4..021592798a 100644 +index db9a421..0215927 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -531,10 +531,12 @@ static void loongarch_cpu_reset_hold(Object *obj) @@ -36,7 +36,7 @@ index db9a421cc4..021592798a 100644 env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h -index 00d1fba597..f6d5ef0852 100644 +index 00d1fba..f6d5ef0 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -319,6 +319,7 @@ typedef struct CPUArchState { @@ -56,5 +56,5 @@ index 00d1fba597..f6d5ef0852 100644 #ifndef CONFIG_USER_ONLY LoongArchTLB tlb[LOONGARCH_TLB_MAX]; -- -2.33.0 +1.8.3.1 diff --git a/0011-target-loongarch-Implement-kvm-get-set-registers.patch b/0156-target-loongarch-Implement-kvm-get-set-registers.patch similarity index 98% rename from 0011-target-loongarch-Implement-kvm-get-set-registers.patch rename to 0156-target-loongarch-Implement-kvm-get-set-registers.patch index 254e53117e6714645504639bb59896fa9cb5f256..0880a8d2190433f67e643b4dc7bb8b49d57e90a7 100644 --- a/0011-target-loongarch-Implement-kvm-get-set-registers.patch +++ b/0156-target-loongarch-Implement-kvm-get-set-registers.patch @@ -1,7 +1,7 @@ -From 0884653d8583aaaa5585caf38246518439bcfdfd Mon Sep 17 00:00:00 2001 +From 9de4586ccf82f7630d4c00360af60957e52c857d Mon Sep 17 00:00:00 2001 From: Tianrui Zhao Date: Fri, 5 Jan 2024 15:57:59 +0800 -Subject: [PATCH] target/loongarch: Implement kvm get/set registers +Subject: [PATCH 166/293] target/loongarch: Implement kvm get/set registers Implement kvm_arch_get/set_registers interfaces, many regs can be get/set in the function, such as core regs, csr regs, @@ -18,7 +18,7 @@ Signed-off-by: Song Gao target/loongarch/cpu.c | 3 + target/loongarch/cpu.h | 1 + target/loongarch/internals.h | 5 +- - target/loongarch/kvm/kvm.c | 580 +++++++++++++++++++++++++++++++++- + target/loongarch/kvm/kvm.c | 580 +++++++++++++++++++++++++++++++++++++++++- target/loongarch/trace-events | 11 + target/loongarch/trace.h | 1 + 7 files changed, 599 insertions(+), 3 deletions(-) @@ -26,7 +26,7 @@ Signed-off-by: Song Gao create mode 100644 target/loongarch/trace.h diff --git a/meson.build b/meson.build -index 6c77d9687d..445f2b7c2b 100644 +index 6c77d96..445f2b7 100644 --- a/meson.build +++ b/meson.build @@ -3358,6 +3358,7 @@ if have_system or have_user @@ -38,7 +38,7 @@ index 6c77d9687d..445f2b7c2b 100644 'target/nios2', 'target/ppc', diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c -index 021592798a..275833eec8 100644 +index 0215927..275833e 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -553,6 +553,9 @@ static void loongarch_cpu_reset_hold(Object *obj) @@ -52,7 +52,7 @@ index 021592798a..275833eec8 100644 restore_fp_status(env); diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h -index f6d5ef0852..f4a89bd626 100644 +index f6d5ef0..f4a89bd 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -360,6 +360,7 @@ typedef struct CPUArchState { @@ -64,7 +64,7 @@ index f6d5ef0852..f4a89bd626 100644 DeviceState *ipistate; #endif diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h -index c492863cc5..0beb034748 100644 +index c492863..0beb034 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -31,8 +31,10 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env, @@ -94,7 +94,7 @@ index c492863cc5..0beb034748 100644 uint64_t read_fcc(CPULoongArchState *env); diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index 0d67322fd9..e7c9ef830c 100644 +index 0d67322..e7c9ef8 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -26,19 +26,595 @@ @@ -697,7 +697,7 @@ index 0d67322fd9..e7c9ef830c 100644 int kvm_arch_init_vcpu(CPUState *cs) diff --git a/target/loongarch/trace-events b/target/loongarch/trace-events new file mode 100644 -index 0000000000..6827ab566a +index 0000000..6827ab5 --- /dev/null +++ b/target/loongarch/trace-events @@ -0,0 +1,11 @@ @@ -714,11 +714,11 @@ index 0000000000..6827ab566a +kvm_failed_put_cpucfg(const char *msg) "Failed to put cpucfg into KVM: %s" diff --git a/target/loongarch/trace.h b/target/loongarch/trace.h new file mode 100644 -index 0000000000..c2ecb78f08 +index 0000000..c2ecb78 --- /dev/null +++ b/target/loongarch/trace.h @@ -0,0 +1 @@ +#include "trace/trace-target_loongarch.h" -- -2.33.0 +1.8.3.1 diff --git a/0012-target-loongarch-Implement-kvm_arch_init-function.patch b/0157-target-loongarch-Implement-kvm_arch_init-function.patch similarity index 84% rename from 0012-target-loongarch-Implement-kvm_arch_init-function.patch rename to 0157-target-loongarch-Implement-kvm_arch_init-function.patch index 73039706ffc02bef62fcc4fd3da65dd4e11ce44d..c50a7c664c236b0bad65b527cce27de1084475db 100644 --- a/0012-target-loongarch-Implement-kvm_arch_init-function.patch +++ b/0157-target-loongarch-Implement-kvm_arch_init-function.patch @@ -1,7 +1,7 @@ -From 3a87dbd5e0343ee777bac0f18888a5a2d51254db Mon Sep 17 00:00:00 2001 +From 43df22a11a199d14cf22c0cda1d88613016cc2a2 Mon Sep 17 00:00:00 2001 From: Tianrui Zhao Date: Fri, 5 Jan 2024 15:58:00 +0800 -Subject: [PATCH] target/loongarch: Implement kvm_arch_init function +Subject: [PATCH 167/293] target/loongarch: Implement kvm_arch_init function Implement the kvm_arch_init of loongarch, in the function, the KVM_CAP_MP_STATE cap is checked by kvm ioctl. @@ -17,7 +17,7 @@ Signed-off-by: Song Gao 1 file changed, 1 insertion(+) diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index e7c9ef830c..29944b9ef8 100644 +index e7c9ef8..29944b9 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -665,6 +665,7 @@ int kvm_arch_get_default_type(MachineState *ms) @@ -29,5 +29,5 @@ index e7c9ef830c..29944b9ef8 100644 } -- -2.33.0 +1.8.3.1 diff --git a/0013-target-loongarch-Implement-kvm_arch_init_vcpu.patch b/0158-target-loongarch-Implement-kvm_arch_init_vcpu.patch similarity index 92% rename from 0013-target-loongarch-Implement-kvm_arch_init_vcpu.patch rename to 0158-target-loongarch-Implement-kvm_arch_init_vcpu.patch index 28fce6870489e576d8dfb77b1f077326d22abd79..53cef48e9049c3463904386aeffc3ada3aff0ff0 100644 --- a/0013-target-loongarch-Implement-kvm_arch_init_vcpu.patch +++ b/0158-target-loongarch-Implement-kvm_arch_init_vcpu.patch @@ -1,7 +1,7 @@ -From d7d47c044c9854675b75b91ade678d03316d9271 Mon Sep 17 00:00:00 2001 +From 1750164e5521ad2b853be4575c4c410f02db46c6 Mon Sep 17 00:00:00 2001 From: Tianrui Zhao Date: Fri, 5 Jan 2024 15:58:01 +0800 -Subject: [PATCH] target/loongarch: Implement kvm_arch_init_vcpu +Subject: [PATCH 168/293] target/loongarch: Implement kvm_arch_init_vcpu Implement kvm_arch_init_vcpu interface for loongarch, in this function, we register VM change state handler. @@ -22,7 +22,7 @@ Signed-off-by: Song Gao 3 files changed, 27 insertions(+) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h -index f4a89bd626..8ebd6fa1a7 100644 +index f4a89bd..8ebd6fa 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -381,6 +381,8 @@ struct ArchCPU { @@ -35,7 +35,7 @@ index f4a89bd626..8ebd6fa1a7 100644 /** diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index 29944b9ef8..85e7aeb083 100644 +index 29944b9..85e7aeb 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -617,8 +617,31 @@ int kvm_arch_put_registers(CPUState *cs, int level) @@ -71,7 +71,7 @@ index 29944b9ef8..85e7aeb083 100644 } diff --git a/target/loongarch/trace-events b/target/loongarch/trace-events -index 6827ab566a..937c3c7c0c 100644 +index 6827ab5..937c3c7 100644 --- a/target/loongarch/trace-events +++ b/target/loongarch/trace-events @@ -7,5 +7,7 @@ kvm_failed_get_fpu(const char *msg) "Failed to get fpu from KVM: %s" @@ -83,5 +83,5 @@ index 6827ab566a..937c3c7c0c 100644 kvm_failed_get_cpucfg(const char *msg) "Failed to get cpucfg from KVM: %s" kvm_failed_put_cpucfg(const char *msg) "Failed to put cpucfg into KVM: %s" -- -2.33.0 +1.8.3.1 diff --git a/0014-target-loongarch-Implement-kvm_arch_handle_exit.patch b/0159-target-loongarch-Implement-kvm_arch_handle_exit.patch similarity index 91% rename from 0014-target-loongarch-Implement-kvm_arch_handle_exit.patch rename to 0159-target-loongarch-Implement-kvm_arch_handle_exit.patch index 46ea9acf4dd1983f0fe66f1192fc32229117fdbf..2c9b3f9bc65f1eb35c355937d23b8e8dd6f14192 100644 --- a/0014-target-loongarch-Implement-kvm_arch_handle_exit.patch +++ b/0159-target-loongarch-Implement-kvm_arch_handle_exit.patch @@ -1,7 +1,7 @@ -From 3feeca228b010716aacdf7159df10ea63f7e34cd Mon Sep 17 00:00:00 2001 +From 7bad21439762c381162f0846a74427bff3f270d3 Mon Sep 17 00:00:00 2001 From: Tianrui Zhao Date: Fri, 5 Jan 2024 15:58:02 +0800 -Subject: [PATCH] target/loongarch: Implement kvm_arch_handle_exit +Subject: [PATCH 169/293] target/loongarch: Implement kvm_arch_handle_exit Implement kvm_arch_handle_exit for loongarch. In this function, the KVM_EXIT_LOONGARCH_IOCSR is handled, @@ -20,7 +20,7 @@ Signed-off-by: Song Gao 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index 85e7aeb083..d2dab3fef4 100644 +index 85e7aeb..d2dab3f 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -723,7 +723,29 @@ bool kvm_arch_cpu_check_are_resettable(void) @@ -55,7 +55,7 @@ index 85e7aeb083..d2dab3fef4 100644 void kvm_arch_accel_class_init(ObjectClass *oc) diff --git a/target/loongarch/trace-events b/target/loongarch/trace-events -index 937c3c7c0c..021839880e 100644 +index 937c3c7..0218398 100644 --- a/target/loongarch/trace-events +++ b/target/loongarch/trace-events @@ -11,3 +11,4 @@ kvm_failed_get_counter(const char *msg) "Failed to get counter from KVM: %s" @@ -64,5 +64,5 @@ index 937c3c7c0c..021839880e 100644 kvm_failed_put_cpucfg(const char *msg) "Failed to put cpucfg into KVM: %s" +kvm_arch_handle_exit(int num) "kvm arch handle exit, the reason number: %d" -- -2.33.0 +1.8.3.1 diff --git a/0015-target-loongarch-Restrict-TCG-specific-code.patch b/0160-target-loongarch-Restrict-TCG-specific-code.patch similarity index 70% rename from 0015-target-loongarch-Restrict-TCG-specific-code.patch rename to 0160-target-loongarch-Restrict-TCG-specific-code.patch index d107009d68ea6289f7e51428d5edc60b4d925adf..1717063b8099181a23fd6e535010327983df4d9b 100644 --- a/0015-target-loongarch-Restrict-TCG-specific-code.patch +++ b/0160-target-loongarch-Restrict-TCG-specific-code.patch @@ -1,59 +1,17 @@ -From 773ea71519da1413ca2e0e60857272164e156a47 Mon Sep 17 00:00:00 2001 +From f178925f4237a13254d8b605cb2867b4751bd889 Mon Sep 17 00:00:00 2001 From: Tianrui Zhao Date: Wed, 10 Jan 2024 10:41:51 +0100 -Subject: [PATCH] target/loongarch: Restrict TCG-specific code -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit +Subject: [PATCH 170/293] target/loongarch: Restrict TCG-specific code In preparation of supporting KVM in the next commit. Conflict: - -diff --cc target/loongarch/cpu.c -index 275833eec8,70dd4622aa..0000000000 ---- a/target/loongarch/cpu.c -+++ b/target/loongarch/cpu.c -@@@ -17,9 -17,14 +17,17 @@@ - #include "internals.h" - #include "fpu/softfloat-helpers.h" - #include "cpu-csr.h" - -#ifndef CONFIG_USER_ONLY - #include "sysemu/reset.h" -++<<<<<<< HEAD - +#include "tcg/tcg.h" -++======= -+ #endif -++>>>>>>> target/loongarch: Restrict TCG-specific code - #include "vec.h" -+ #ifdef CONFIG_TCG -+ #include "exec/cpu_ldst.h" -+ #include "tcg/tcg.h" -+ #endif - -Solve: - -drop: -++<<<<<<< HEAD - +#include "tcg/tcg.h" -++======= -+ #endif -++>>>>>>> target/loongarch: Restrict TCG-specific code - -Signed-off-by: Tianrui Zhao -Signed-off-by: xianglai li -Reviewed-by: Song Gao -Message-ID: <20240105075804.1228596-9-zhaotianrui@loongson.cn> -[PMD: Split from bigger patch, part 1] -Signed-off-by: Philippe Mathieu-Daudé -Message-Id: <20240110094152.52138-1-philmd@linaro.org> -Signed-off-by: Song Gao --- target/loongarch/cpu.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c -index 275833eec8..60f2636b43 100644 +index 275833e..60f2636 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -11,15 +11,18 @@ @@ -148,5 +106,5 @@ index 275833eec8..60f2636b43 100644 static int64_t loongarch_cpu_get_arch_id(CPUState *cs) -- -2.33.0 +1.8.3.1 diff --git a/0016-target-loongarch-Implement-set-vcpu-intr-for-kvm.patch b/0161-target-loongarch-Implement-set-vcpu-intr-for-kvm.patch similarity index 93% rename from 0016-target-loongarch-Implement-set-vcpu-intr-for-kvm.patch rename to 0161-target-loongarch-Implement-set-vcpu-intr-for-kvm.patch index d8a58be33653bdbbcf3484d872ba08c316f7f973..5a58a8e33e6a495db866e582ea3254b041b3a87e 100644 --- a/0016-target-loongarch-Implement-set-vcpu-intr-for-kvm.patch +++ b/0161-target-loongarch-Implement-set-vcpu-intr-for-kvm.patch @@ -1,7 +1,7 @@ -From 5f4c8b31db442e6ac39fbfe4b29d5479ab3567aa Mon Sep 17 00:00:00 2001 +From a616f6dcf7bd84d572da86290fcdf544e2410b41 Mon Sep 17 00:00:00 2001 From: Tianrui Zhao Date: Wed, 10 Jan 2024 10:41:52 +0100 -Subject: [PATCH] target/loongarch: Implement set vcpu intr for kvm +Subject: [PATCH 171/293] target/loongarch: Implement set vcpu intr for kvm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -27,7 +27,7 @@ Signed-off-by: Song Gao create mode 100644 target/loongarch/kvm/kvm_loongarch.h diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c -index 60f2636b43..413414392b 100644 +index 60f2636..4134143 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -12,6 +12,8 @@ @@ -61,7 +61,7 @@ index 60f2636b43..413414392b 100644 if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) { cpu_interrupt(cs, CPU_INTERRUPT_HARD); diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index d2dab3fef4..bd33ec2114 100644 +index d2dab3f..bd33ec2 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -748,6 +748,21 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) @@ -88,7 +88,7 @@ index d2dab3fef4..bd33ec2114 100644 } diff --git a/target/loongarch/kvm/kvm_loongarch.h b/target/loongarch/kvm/kvm_loongarch.h new file mode 100644 -index 0000000000..d945b6bb82 +index 0000000..d945b6b --- /dev/null +++ b/target/loongarch/kvm/kvm_loongarch.h @@ -0,0 +1,16 @@ @@ -109,7 +109,7 @@ index 0000000000..d945b6bb82 + +#endif diff --git a/target/loongarch/trace-events b/target/loongarch/trace-events -index 021839880e..dea11edc0f 100644 +index 0218398..dea11ed 100644 --- a/target/loongarch/trace-events +++ b/target/loongarch/trace-events @@ -12,3 +12,4 @@ kvm_failed_put_counter(const char *msg) "Failed to put counter into KVM: %s" @@ -118,5 +118,5 @@ index 021839880e..dea11edc0f 100644 kvm_arch_handle_exit(int num) "kvm arch handle exit, the reason number: %d" +kvm_set_intr(int irq, int level) "kvm set interrupt, irq num: %d, level: %d" -- -2.33.0 +1.8.3.1 diff --git a/0017-target-loongarch-Add-loongarch-kvm-into-meson-build.patch b/0162-target-loongarch-Add-loongarch-kvm-into-meson-build.patch similarity index 87% rename from 0017-target-loongarch-Add-loongarch-kvm-into-meson-build.patch rename to 0162-target-loongarch-Add-loongarch-kvm-into-meson-build.patch index 4379887adeb46f6ed2fd1b29534f2b6b06f9d9f4..feddfd95d259da0deb384d0212b7a51d7bee2c0b 100644 --- a/0017-target-loongarch-Add-loongarch-kvm-into-meson-build.patch +++ b/0162-target-loongarch-Add-loongarch-kvm-into-meson-build.patch @@ -1,7 +1,7 @@ -From 49a7ae85d6ac42f8ef556a0d42802508c28adfcc Mon Sep 17 00:00:00 2001 +From 18985e1df4b75b3cf442c7a503d1092457000f0a Mon Sep 17 00:00:00 2001 From: Tianrui Zhao Date: Fri, 5 Jan 2024 15:58:04 +0800 -Subject: [PATCH] target/loongarch: Add loongarch kvm into meson build +Subject: [PATCH 172/293] target/loongarch: Add loongarch kvm into meson build Add kvm.c into meson.build to compile it when kvm is configed. Meanwhile in meson.build, we set the @@ -23,7 +23,7 @@ Signed-off-by: Song Gao create mode 100644 target/loongarch/kvm/meson.build diff --git a/meson.build b/meson.build -index 445f2b7c2b..0c62b4156d 100644 +index 445f2b7..0c62b41 100644 --- a/meson.build +++ b/meson.build @@ -114,6 +114,8 @@ elif cpu in ['riscv32'] @@ -37,13 +37,13 @@ index 445f2b7c2b..0c62b4156d 100644 endif diff --git a/target/loongarch/kvm/meson.build b/target/loongarch/kvm/meson.build new file mode 100644 -index 0000000000..2266de6ca9 +index 0000000..2266de6 --- /dev/null +++ b/target/loongarch/kvm/meson.build @@ -0,0 +1 @@ +loongarch_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build -index e84e4c51f4..db310f6022 100644 +index e84e4c5..db310f6 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -18,3 +18,4 @@ subdir('tcg') @@ -52,5 +52,5 @@ index e84e4c51f4..db310f6022 100644 target_system_arch += {'loongarch': loongarch_system_ss} +subdir('kvm') -- -2.33.0 +1.8.3.1 diff --git a/0018-hw-intc-loongarch_ipi-Use-MemTxAttrs-interface-for-i.patch b/0163-hw-intc-loongarch_ipi-Use-MemTxAttrs-interface-for-i.patch similarity index 97% rename from 0018-hw-intc-loongarch_ipi-Use-MemTxAttrs-interface-for-i.patch rename to 0163-hw-intc-loongarch_ipi-Use-MemTxAttrs-interface-for-i.patch index d15294229a5a7712f5635bd8f1e5bdf156498af2..206f576ac1c7493a94d641ae1e25bcd6306636c8 100644 --- a/0018-hw-intc-loongarch_ipi-Use-MemTxAttrs-interface-for-i.patch +++ b/0163-hw-intc-loongarch_ipi-Use-MemTxAttrs-interface-for-i.patch @@ -1,8 +1,8 @@ -From b8f53cfa91e86d5163318f8ade1cca18e94f3eb7 Mon Sep 17 00:00:00 2001 +From cb6d7101b94bfaed19c2a208990345c854d014e4 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 13 Dec 2023 12:12:01 +0800 -Subject: [PATCH] hw/intc/loongarch_ipi: Use MemTxAttrs interface for ipi - ops +Subject: [PATCH 173/293] hw/intc/loongarch_ipi: Use MemTxAttrs interface for + ipi ops There are two interface pairs for MemoryRegionOps, read/write and read_with_attrs/write_with_attrs. The later is better for ipi device @@ -16,11 +16,11 @@ Reviewed-by: Song Gao Message-Id: <20231215100333.3933632-2-maobibo@loongson.cn> Signed-off-by: Song Gao --- - hw/intc/loongarch_ipi.c | 136 +++++++++++++++++++++++----------------- + hw/intc/loongarch_ipi.c | 136 +++++++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 59 deletions(-) diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c -index 67858b521c..221246c5cb 100644 +index 67858b5..221246c 100644 --- a/hw/intc/loongarch_ipi.c +++ b/hw/intc/loongarch_ipi.c @@ -17,14 +17,16 @@ @@ -283,5 +283,5 @@ index 67858b521c..221246c5cb 100644 qdev_init_gpio_out(DEVICE(obj), &s->ipi_core.irq, 1); } -- -2.33.0 +1.8.3.1 diff --git a/0019-hw-loongarch-virt-Set-iocsr-address-space-per-board-.patch b/0164-hw-loongarch-virt-Set-iocsr-address-space-per-board-.patch similarity index 95% rename from 0019-hw-loongarch-virt-Set-iocsr-address-space-per-board-.patch rename to 0164-hw-loongarch-virt-Set-iocsr-address-space-per-board-.patch index 2af282db34fa2b0df1e598446994afb38f1985ae..611fedf7649d56615f271c5e04f877de17e8fba6 100644 --- a/0019-hw-loongarch-virt-Set-iocsr-address-space-per-board-.patch +++ b/0164-hw-loongarch-virt-Set-iocsr-address-space-per-board-.patch @@ -1,7 +1,7 @@ -From 43100bba2bfd9de0c3bab7c3e815b02faa69242d Mon Sep 17 00:00:00 2001 +From 8dcb2d7c9fd5691a337c1a1c59d3d8d68bd1922c Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 13 Dec 2023 12:13:14 +0800 -Subject: [PATCH] hw/loongarch/virt: Set iocsr address space per-board +Subject: [PATCH 174/293] hw/loongarch/virt: Set iocsr address space per-board rather than percpu LoongArch system has iocsr address space, most iocsr registers are @@ -38,20 +38,20 @@ Reviewed-by: Song Gao Message-Id: <20231215100333.3933632-3-maobibo@loongson.cn> Signed-off-by: Song Gao --- - hw/intc/loongarch_extioi.c | 3 - - hw/intc/loongarch_ipi.c | 63 +++++++++++++++----- - hw/loongarch/virt.c | 91 +++++++++++++++++++++-------- + hw/intc/loongarch_extioi.c | 3 -- + hw/intc/loongarch_ipi.c | 63 ++++++++++++++++++------- + hw/loongarch/virt.c | 91 +++++++++++++++++++++++++++---------- include/hw/intc/loongarch_extioi.h | 1 - include/hw/intc/loongarch_ipi.h | 3 +- - include/hw/loongarch/virt.h | 3 + - target/loongarch/cpu.c | 48 --------------- + include/hw/loongarch/virt.h | 3 ++ + target/loongarch/cpu.c | 48 ------------------- target/loongarch/cpu.h | 4 +- target/loongarch/kvm/kvm.c | 2 +- - target/loongarch/tcg/iocsr_helper.c | 16 ++--- + target/loongarch/tcg/iocsr_helper.c | 16 +++---- 10 files changed, 129 insertions(+), 105 deletions(-) diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c -index 24fb3af8cc..77b4776958 100644 +index 24fb3af..77b4776 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -282,9 +282,6 @@ static void loongarch_extioi_instance_init(Object *obj) @@ -65,7 +65,7 @@ index 24fb3af8cc..77b4776958 100644 qdev_init_gpio_out(DEVICE(obj), &s->parent_irq[cpu][pin], 1); } diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c -index 221246c5cb..e228669aa5 100644 +index 221246c..e228669 100644 --- a/hw/intc/loongarch_ipi.c +++ b/hw/intc/loongarch_ipi.c @@ -9,6 +9,7 @@ @@ -215,7 +215,7 @@ index 221246c5cb..e228669aa5 100644 static void loongarch_ipi_register_types(void) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c -index 4b7dc67a2d..13d19b6da3 100644 +index 4b7dc67..13d19b6 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -535,9 +535,6 @@ static void loongarch_irq_init(LoongArchMachineState *lams) @@ -349,7 +349,7 @@ index 4b7dc67a2d..13d19b6da3 100644 for (i = 0; i < possible_cpus->len; i++) { cpu = cpu_create(machine->cpu_type); diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h -index fbdef9a7b3..110e5e8873 100644 +index fbdef9a..110e5e8 100644 --- a/include/hw/intc/loongarch_extioi.h +++ b/include/hw/intc/loongarch_extioi.h @@ -58,7 +58,6 @@ struct LoongArchExtIOI { @@ -361,7 +361,7 @@ index fbdef9a7b3..110e5e8873 100644 }; #endif /* LOONGARCH_EXTIOI_H */ diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h -index 6c6194786e..1c1e834849 100644 +index 6c61947..1c1e834 100644 --- a/include/hw/intc/loongarch_ipi.h +++ b/include/hw/intc/loongarch_ipi.h @@ -47,7 +47,8 @@ struct LoongArchIPI { @@ -375,7 +375,7 @@ index 6c6194786e..1c1e834849 100644 #endif diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h -index db0831b471..6ef9a92394 100644 +index db0831b..6ef9a92 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -50,6 +50,9 @@ struct LoongArchMachineState { @@ -389,7 +389,7 @@ index db0831b471..6ef9a92394 100644 #define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c -index 413414392b..6611d137a1 100644 +index 4134143..6611d13 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -602,47 +602,6 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) @@ -461,7 +461,7 @@ index 413414392b..6611d137a1 100644 } diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h -index 8ebd6fa1a7..4aba8aba4c 100644 +index 8ebd6fa..4aba8ab 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -355,9 +355,7 @@ typedef struct CPUArchState { @@ -476,7 +476,7 @@ index 8ebd6fa1a7..4aba8aba4c 100644 uint64_t elf_address; uint32_t mp_state; diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index bd33ec2114..84bcdf5f86 100644 +index bd33ec2..84bcdf5 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -733,7 +733,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) @@ -489,7 +489,7 @@ index bd33ec2114..84bcdf5f86 100644 attrs, run->iocsr_io.data, diff --git a/target/loongarch/tcg/iocsr_helper.c b/target/loongarch/tcg/iocsr_helper.c -index 6cd01d5f09..b6916f53d2 100644 +index 6cd01d5..b6916f5 100644 --- a/target/loongarch/tcg/iocsr_helper.c +++ b/target/loongarch/tcg/iocsr_helper.c @@ -17,52 +17,52 @@ @@ -554,5 +554,5 @@ index 6cd01d5f09..b6916f53d2 100644 val, GET_MEMTXATTRS(env), NULL); } -- -2.33.0 +1.8.3.1 diff --git a/0020-hw-intc-loongarch_extioi-Add-dynamic-cpu-number-supp.patch b/0165-hw-intc-loongarch_extioi-Add-dynamic-cpu-number-supp.patch similarity index 96% rename from 0020-hw-intc-loongarch_extioi-Add-dynamic-cpu-number-supp.patch rename to 0165-hw-intc-loongarch_extioi-Add-dynamic-cpu-number-supp.patch index 110b4e6f7369e42d8fc046ef463fb92bca8dbcaa..dc9c8cbcc210f9387180c772e66e7daec14985de 100644 --- a/0020-hw-intc-loongarch_extioi-Add-dynamic-cpu-number-supp.patch +++ b/0165-hw-intc-loongarch_extioi-Add-dynamic-cpu-number-supp.patch @@ -1,7 +1,7 @@ -From 4440ab99f7f7b04ef79f6b35b8330edf7fe66002 Mon Sep 17 00:00:00 2001 +From 1371453256d44a02fe4c6fe9c42724e85e56fe52 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 15 Dec 2023 11:07:36 +0800 -Subject: [PATCH] hw/intc/loongarch_extioi: Add dynamic cpu number +Subject: [PATCH 175/293] hw/intc/loongarch_extioi: Add dynamic cpu number support On LoongArch physical machine, one extioi interrupt controller only @@ -45,13 +45,13 @@ Reviewed-by: Song Gao Message-Id: <20231215100333.3933632-4-maobibo@loongson.cn> Signed-off-by: Song Gao --- - hw/intc/loongarch_extioi.c | 109 +++++++++++++++++++---------- + hw/intc/loongarch_extioi.c | 109 ++++++++++++++++++++++++------------- hw/loongarch/virt.c | 3 +- - include/hw/intc/loongarch_extioi.h | 11 ++- + include/hw/intc/loongarch_extioi.h | 11 +++- 3 files changed, 82 insertions(+), 41 deletions(-) diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c -index 77b4776958..28802bf3ef 100644 +index 77b4776..28802bf 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -8,6 +8,7 @@ @@ -236,7 +236,7 @@ index 77b4776958..28802bf3ef 100644 static void loongarch_extioi_register_types(void) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c -index 13d19b6da3..c9a680e61a 100644 +index 13d19b6..c9a680e 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -582,6 +582,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) @@ -257,7 +257,7 @@ index 13d19b6da3..c9a680e61a 100644 for (pin = 0; pin < LS3A_INTC_IP; pin++) { qdev_connect_gpio_out(extioi, (cpu * 8 + pin), diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h -index 110e5e8873..a0a46b888c 100644 +index 110e5e8..a0a46b8 100644 --- a/include/hw/intc/loongarch_extioi.h +++ b/include/hw/intc/loongarch_extioi.h @@ -40,24 +40,29 @@ @@ -294,5 +294,5 @@ index 110e5e8873..a0a46b888c 100644 }; #endif /* LOONGARCH_EXTIOI_H */ -- -2.33.0 +1.8.3.1 diff --git a/0021-hw-intc-loongarch_extioi-Add-vmstate-post_load-suppo.patch b/0166-hw-intc-loongarch_extioi-Add-vmstate-post_load-suppo.patch similarity index 96% rename from 0021-hw-intc-loongarch_extioi-Add-vmstate-post_load-suppo.patch rename to 0166-hw-intc-loongarch_extioi-Add-vmstate-post_load-suppo.patch index 45385d3daba4738aec1a83ca1f15554c469ea804..e27d832ef00e17a0615e9d65cc09657ddaea75f9 100644 --- a/0021-hw-intc-loongarch_extioi-Add-vmstate-post_load-suppo.patch +++ b/0166-hw-intc-loongarch_extioi-Add-vmstate-post_load-suppo.patch @@ -1,7 +1,8 @@ -From db8c355d923c218c5ca373c4acd5d13493152889 Mon Sep 17 00:00:00 2001 +From 5202b8db3da24f8d94e761835040cf39457adb49 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 15 Dec 2023 17:42:58 +0800 -Subject: [PATCH] hw/intc/loongarch_extioi: Add vmstate post_load support +Subject: [PATCH 176/293] hw/intc/loongarch_extioi: Add vmstate post_load + support There are elements sw_ipmap and sw_coremap, which is usd to speed up irq injection flow. They are saved and restored in vmstate during @@ -14,11 +15,11 @@ Reviewed-by: Song Gao Message-Id: <20231215100333.3933632-5-maobibo@loongson.cn> Signed-off-by: Song Gao --- - hw/intc/loongarch_extioi.c | 120 +++++++++++++++++++++++-------------- + hw/intc/loongarch_extioi.c | 120 ++++++++++++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 44 deletions(-) diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c -index 28802bf3ef..bdfa3b481e 100644 +index 28802bf..bdfa3b4 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -130,12 +130,66 @@ static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\ @@ -189,5 +190,5 @@ index 28802bf3ef..bdfa3b481e 100644 VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOI, num_cpu, vmstate_extioi_core, ExtIOICore), -- -2.33.0 +1.8.3.1 diff --git a/0022-configure-Add-linux-header-compile-support-for-Loong.patch b/0167-configure-Add-linux-header-compile-support-for-Loong.patch similarity index 86% rename from 0022-configure-Add-linux-header-compile-support-for-Loong.patch rename to 0167-configure-Add-linux-header-compile-support-for-Loong.patch index ceb5a37de9380bc59271514a63f046fa4bc36650..6e6f72adbd4099c2a648967f1b66b10f356d7832 100644 --- a/0022-configure-Add-linux-header-compile-support-for-Loong.patch +++ b/0167-configure-Add-linux-header-compile-support-for-Loong.patch @@ -1,7 +1,7 @@ -From b21a705562867cc9dcbf0012ffa200caad8458ba Mon Sep 17 00:00:00 2001 +From f8d33f5e009dbc9cf698f02306559042449b7edd Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 16 Jan 2024 09:39:52 +0800 -Subject: [PATCH] configure: Add linux header compile support for +Subject: [PATCH 177/293] configure: Add linux header compile support for LoongArch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -25,7 +25,7 @@ Signed-off-by: Philippe Mathieu-Daudé 1 file changed, 1 insertion(+) diff --git a/configure b/configure -index bdda912f36..6036de83a4 100755 +index d3ab436..0609aa9 100755 --- a/configure +++ b/configure @@ -445,6 +445,7 @@ case "$cpu" in @@ -37,5 +37,5 @@ index bdda912f36..6036de83a4 100755 mips64*) -- -2.33.0 +1.8.3.1 diff --git a/0023-target-loongarch-Set-cpuid-CSR-register-only-once-wi.patch b/0168-target-loongarch-Set-cpuid-CSR-register-only-once-wi.patch similarity index 90% rename from 0023-target-loongarch-Set-cpuid-CSR-register-only-once-wi.patch rename to 0168-target-loongarch-Set-cpuid-CSR-register-only-once-wi.patch index e008764d76f3a8aa130eca6d0d5b28b1ee1e93ce..bb45f25d635f3ee2f64eb2ff5ff8bebcde77c253 100644 --- a/0023-target-loongarch-Set-cpuid-CSR-register-only-once-wi.patch +++ b/0168-target-loongarch-Set-cpuid-CSR-register-only-once-wi.patch @@ -1,8 +1,8 @@ -From d271f623205c2984a30cfb12e160e219b2bbe974 Mon Sep 17 00:00:00 2001 +From ca7498455d5a5bc210e566ea2d2366be333eebe6 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Mon, 15 Jan 2024 16:51:21 +0800 -Subject: [PATCH] target/loongarch: Set cpuid CSR register only once with - kvm mode +Subject: [PATCH 178/293] target/loongarch: Set cpuid CSR register only once + with kvm mode CSR cpuid register is used for routing irq to different vcpus, its value is kept unchanged since poweron. So it is not necessary to @@ -18,7 +18,7 @@ Signed-off-by: Song Gao 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index 84bcdf5f86..2230f029d0 100644 +index 84bcdf5..2230f02 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -250,7 +250,7 @@ static int kvm_loongarch_get_csr(CPUState *cs) @@ -53,5 +53,5 @@ index 84bcdf5f86..2230f029d0 100644 return ret; } -- -2.33.0 +1.8.3.1 diff --git a/0024-target-loongarch-kvm-Enable-LSX-LASX-extension.patch b/0169-target-loongarch-kvm-Enable-LSX-LASX-extension.patch similarity index 93% rename from 0024-target-loongarch-kvm-Enable-LSX-LASX-extension.patch rename to 0169-target-loongarch-kvm-Enable-LSX-LASX-extension.patch index 6d08d3e8ad09ce3bd1dd65b2884a3e7a3db0255a..ef95924e245fd1ef64242d1c5d5960861deb594d 100644 --- a/0024-target-loongarch-kvm-Enable-LSX-LASX-extension.patch +++ b/0169-target-loongarch-kvm-Enable-LSX-LASX-extension.patch @@ -1,7 +1,7 @@ -From 6e503b590e42ad7c522cf937b83e1f8f715dbd1a Mon Sep 17 00:00:00 2001 +From 800546d35c63ca459a8d03b6306fd114dea6c38a Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 22 Jan 2024 17:02:06 +0800 -Subject: [PATCH] target/loongarch/kvm: Enable LSX/LASX extension +Subject: [PATCH 179/293] target/loongarch/kvm: Enable LSX/LASX extension The kernel had already support LSX and LASX [1], but QEMU is disable LSX/LASX for kvm. This patch adds @@ -14,11 +14,11 @@ Reviewed-by: Bibo Mao Message-Id: <20240122090206.1083584-1-gaosong@loongson.cn> --- linux-headers/asm-loongarch/kvm.h | 1 + - target/loongarch/kvm/kvm.c | 45 ++++++++++++++++++++++++++----- + target/loongarch/kvm/kvm.c | 45 +++++++++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h -index c6ad2ee610..923d0bd382 100644 +index c6ad2ee..923d0bd 100644 --- a/linux-headers/asm-loongarch/kvm.h +++ b/linux-headers/asm-loongarch/kvm.h @@ -79,6 +79,7 @@ struct kvm_fpu { @@ -30,7 +30,7 @@ index c6ad2ee610..923d0bd382 100644 struct kvm_debug_exit_arch { }; diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index 2230f029d0..c19978a970 100644 +index 2230f02..c19978a 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -540,6 +540,38 @@ static int kvm_loongarch_get_cpucfg(CPUState *cs) @@ -94,5 +94,5 @@ index 2230f029d0..c19978a970 100644 if (ret < 0) { trace_kvm_failed_put_cpucfg(strerror(errno)); -- -2.33.0 +1.8.3.1 diff --git a/0025-target-loongarch-Fix-qtest-test-hmp-error-when-KVM-o.patch b/0170-target-loongarch-Fix-qtest-test-hmp-error-when-KVM-o.patch similarity index 98% rename from 0025-target-loongarch-Fix-qtest-test-hmp-error-when-KVM-o.patch rename to 0170-target-loongarch-Fix-qtest-test-hmp-error-when-KVM-o.patch index 4c4a84ce256078da58609911feec782d24a1266e..54c8bf601d5e2ed304cb733f1c080cdf9dc3b449 100644 --- a/0025-target-loongarch-Fix-qtest-test-hmp-error-when-KVM-o.patch +++ b/0170-target-loongarch-Fix-qtest-test-hmp-error-when-KVM-o.patch @@ -1,7 +1,7 @@ -From d2381abc2c78de68e765a29a55282707541e315d Mon Sep 17 00:00:00 2001 +From 1d921b47aeb51564426cb691900d77aac422f75b Mon Sep 17 00:00:00 2001 From: Song Gao Date: Thu, 25 Jan 2024 14:14:01 +0800 -Subject: [PATCH] target/loongarch: Fix qtest test-hmp error when +Subject: [PATCH 180/293] target/loongarch: Fix qtest test-hmp error when KVM-only build The cc->sysemu_ops->get_phys_page_debug() is NULL when @@ -12,15 +12,15 @@ Tested-by: Bibo Mao Message-Id: <20240125061401.52526-1-gaosong@loongson.cn> --- target/loongarch/cpu.c | 2 - - target/loongarch/cpu_helper.c | 231 ++++++++++++++++++++++++++++++ - target/loongarch/internals.h | 20 ++- + target/loongarch/cpu_helper.c | 231 ++++++++++++++++++++++++++++++++++++++ + target/loongarch/internals.h | 20 +++- target/loongarch/meson.build | 1 + - target/loongarch/tcg/tlb_helper.c | 230 ----------------------------- + target/loongarch/tcg/tlb_helper.c | 230 ------------------------------------- 5 files changed, 250 insertions(+), 234 deletions(-) create mode 100644 target/loongarch/cpu_helper.c diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c -index 6611d137a1..b098b1c6f3 100644 +index 6611d13..b098b1c 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -771,9 +771,7 @@ static struct TCGCPUOps loongarch_tcg_ops = { @@ -35,7 +35,7 @@ index 6611d137a1..b098b1c6f3 100644 static int64_t loongarch_cpu_get_arch_id(CPUState *cs) diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c new file mode 100644 -index 0000000000..f68d63f466 +index 0000000..f68d63f --- /dev/null +++ b/target/loongarch/cpu_helper.c @@ -0,0 +1,231 @@ @@ -271,7 +271,7 @@ index 0000000000..f68d63f466 + return phys_addr; +} diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h -index 0beb034748..a2fc54c8a7 100644 +index 0beb034..a2fc54c 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -37,6 +37,17 @@ void restore_fp_status(CPULoongArchState *env); @@ -313,7 +313,7 @@ index 0beb034748..a2fc54c8a7 100644 #endif /* !CONFIG_USER_ONLY */ diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build -index db310f6022..e002e9aaf6 100644 +index db310f6..e002e9a 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -8,6 +8,7 @@ loongarch_ss.add(files( @@ -325,7 +325,7 @@ index db310f6022..e002e9aaf6 100644 'machine.c', )) diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c -index 449043c68b..804ab7a263 100644 +index 449043c..804ab7a 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -17,236 +17,6 @@ @@ -566,5 +566,5 @@ index 449043c68b..804ab7a263 100644 MMUAccessType access_type, int tlb_error) { -- -2.33.0 +1.8.3.1 diff --git a/0026-loongarch-Change-the-UEFI-loading-mode-to-loongarch.patch b/0171-loongarch-Change-the-UEFI-loading-mode-to-loongarch.patch similarity index 96% rename from 0026-loongarch-Change-the-UEFI-loading-mode-to-loongarch.patch rename to 0171-loongarch-Change-the-UEFI-loading-mode-to-loongarch.patch index e4f939a2b46eb1bdb8107eba482b609bef5b410c..28f6869ee85c366059cf8ad7038b75349bedc109 100644 --- a/0026-loongarch-Change-the-UEFI-loading-mode-to-loongarch.patch +++ b/0171-loongarch-Change-the-UEFI-loading-mode-to-loongarch.patch @@ -1,7 +1,7 @@ -From 4a5a9bef6eff5837dcccd216172957d8470b6245 Mon Sep 17 00:00:00 2001 +From 484be2c61b9b2c9b5ac54ccb7c615e964f4797c0 Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Mon, 19 Feb 2024 18:34:14 +0800 -Subject: [PATCH] loongarch: Change the UEFI loading mode to loongarch +Subject: [PATCH 181/293] loongarch: Change the UEFI loading mode to loongarch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -33,13 +33,13 @@ Reviewed-by: Song Gao Message-Id: <0bd892aa9b88e0f4cc904cb70efd0251fc1cde29.1708336919.git.lixianglai@loongson.cn> Signed-off-by: Song Gao --- - hw/loongarch/acpi-build.c | 29 +++++++++-- - hw/loongarch/virt.c | 101 ++++++++++++++++++++++++++---------- - include/hw/loongarch/virt.h | 10 ++-- + hw/loongarch/acpi-build.c | 29 +++++++++++-- + hw/loongarch/virt.c | 101 ++++++++++++++++++++++++++++++++------------ + include/hw/loongarch/virt.h | 10 +++-- 3 files changed, 107 insertions(+), 33 deletions(-) diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c -index ae292fc543..f990405d04 100644 +index ae292fc..f990405 100644 --- a/hw/loongarch/acpi-build.c +++ b/hw/loongarch/acpi-build.c @@ -314,16 +314,39 @@ static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams) @@ -86,7 +86,7 @@ index ae292fc543..f990405d04 100644 aml_append(scope, dev); } diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c -index c9a680e61a..6ef40fa24a 100644 +index c9a680e..6ef40fa 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -54,7 +54,9 @@ struct loaderparams { @@ -254,7 +254,7 @@ index c9a680e61a..6ef40fa24a 100644 static void reset_load_elf(void *opaque) diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h -index 6ef9a92394..252f7df7f4 100644 +index 6ef9a92..252f7df 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -18,10 +18,12 @@ @@ -283,5 +283,5 @@ index 6ef9a92394..252f7df7f4 100644 MemoryRegion iocsr_mem; AddressSpace as_iocsr; -- -2.33.0 +1.8.3.1 diff --git a/0027-target-loongarch-Fix-tlb-huge-page-loading-issue.patch b/0172-target-loongarch-Fix-tlb-huge-page-loading-issue.patch similarity index 96% rename from 0027-target-loongarch-Fix-tlb-huge-page-loading-issue.patch rename to 0172-target-loongarch-Fix-tlb-huge-page-loading-issue.patch index e351c35e80ff28dee910d5e9cbd1652317e9fc71..8214f3c3a0d4f1b345f540f73f33108990ffa73b 100644 --- a/0027-target-loongarch-Fix-tlb-huge-page-loading-issue.patch +++ b/0172-target-loongarch-Fix-tlb-huge-page-loading-issue.patch @@ -1,7 +1,7 @@ -From f6872e0691c293cdc11353457f5aa89d3fc6fd6a Mon Sep 17 00:00:00 2001 +From b99489d37aa0ee611c67be81e162e36566437d58 Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Mon, 18 Mar 2024 15:03:32 +0800 -Subject: [PATCH] target/loongarch: Fix tlb huge page loading issue +Subject: [PATCH 182/293] target/loongarch: Fix tlb huge page loading issue When we use qemu tcg simulation, the page size of bios is 4KB. When using the level 2 super huge page (page size is 1G) to create the page table, @@ -20,11 +20,11 @@ Message-Id: <20240318070332.1273939-1-lixianglai@loongson.cn> --- target/loongarch/cpu-csr.h | 3 + target/loongarch/internals.h | 5 -- - target/loongarch/tcg/tlb_helper.c | 113 +++++++++++++++++++++--------- + target/loongarch/tcg/tlb_helper.c | 113 ++++++++++++++++++++++++++------------ 3 files changed, 82 insertions(+), 39 deletions(-) diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h -index c59d7a9fcb..0834e91f30 100644 +index c59d7a9..0834e91 100644 --- a/target/loongarch/cpu-csr.h +++ b/target/loongarch/cpu-csr.h @@ -67,6 +67,9 @@ FIELD(TLBENTRY, D, 1, 1) @@ -38,7 +38,7 @@ index c59d7a9fcb..0834e91f30 100644 FIELD(TLBENTRY_64, PPN, 12, 36) FIELD(TLBENTRY_64, NR, 61, 1) diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h -index a2fc54c8a7..944153b180 100644 +index a2fc54c..944153b 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -16,11 +16,6 @@ @@ -54,7 +54,7 @@ index a2fc54c8a7..944153b180 100644 void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c -index 804ab7a263..eedd1ac376 100644 +index 804ab7a..eedd1ac 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -17,6 +17,34 @@ @@ -204,5 +204,5 @@ index 804ab7a263..eedd1ac376 100644 tmp0 += MAKE_64BIT_MASK(ps, 1); } -- -2.33.0 +1.8.3.1 diff --git a/0028-target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch b/0173-target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch similarity index 90% rename from 0028-target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch rename to 0173-target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch index f49bf1b9f98ca15b74519c4ba3188c7f056e2b0e..e0aaabe12bcf8566ae0db9a1671b973b3e846c68 100644 --- a/0028-target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch +++ b/0173-target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch @@ -1,7 +1,7 @@ -From 00cba740b912937535a0ad70b968bc94cd1ba4e5 Mon Sep 17 00:00:00 2001 +From b4c4a14780fc23730594824c7fe0e073fd063ac3 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Wed, 20 Mar 2024 09:39:55 +0800 -Subject: [PATCH] target/loongarch: Fix qemu-loongarch64 hang when +Subject: [PATCH 183/293] target/loongarch: Fix qemu-loongarch64 hang when executing 'll.d $t0, $t0, 0' On gen_ll, if a->imm is zero, make_address_x return src1, @@ -18,7 +18,7 @@ Message-Id: <20240320013955.1561311-1-gaosong@loongson.cn> 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/loongarch/tcg/insn_trans/trans_atomic.c.inc b/target/loongarch/tcg/insn_trans/trans_atomic.c.inc -index 80c2e286fd..974bc2a70f 100644 +index 80c2e28..974bc2a 100644 --- a/target/loongarch/tcg/insn_trans/trans_atomic.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_atomic.c.inc @@ -5,14 +5,14 @@ @@ -41,5 +41,5 @@ index 80c2e286fd..974bc2a70f 100644 return true; } -- -2.33.0 +1.8.3.1 diff --git a/0029-target-loongarch-kvm-Add-software-breakpoint-support.patch b/0174-target-loongarch-kvm-Add-software-breakpoint-support.patch similarity index 94% rename from 0029-target-loongarch-kvm-Add-software-breakpoint-support.patch rename to 0174-target-loongarch-kvm-Add-software-breakpoint-support.patch index 32a8ca81905192bf0b2c47e71f2ddba61c8b14ce..f229d0558860114f9be1f644d2677b999f1905a8 100644 --- a/0029-target-loongarch-kvm-Add-software-breakpoint-support.patch +++ b/0174-target-loongarch-kvm-Add-software-breakpoint-support.patch @@ -1,7 +1,7 @@ -From 3be9d3c66430bb9152bcfc8e2c042292d7450527 Mon Sep 17 00:00:00 2001 +From 1729bc04cb9ff298bbe543dec2c7cbaa316cbf9c Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Sun, 18 Feb 2024 15:00:25 +0800 -Subject: [PATCH] target/loongarch/kvm: Add software breakpoint support +Subject: [PATCH 184/293] target/loongarch/kvm: Add software breakpoint support With KVM virtualization, debug exception is passthrough to to guest kernel rather than host mode. Here hypercall @@ -14,11 +14,11 @@ will be added. Signed-off-by: Bibo Mao --- - target/loongarch/kvm/kvm.c | 77 ++++++++++++++++++++++++++++++++++++++ + target/loongarch/kvm/kvm.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index c19978a970..49d02076ad 100644 +index c19978a..49d0207 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -29,6 +29,7 @@ @@ -128,5 +128,5 @@ index c19978a970..49d02076ad 100644 ret = -1; warn_report("KVM: unknown exit reason %d", run->exit_reason); -- -2.33.0 +1.8.3.1 diff --git a/0030-hw-intc-loongarch_extioi-Add-virt-extension-support.patch b/0175-hw-intc-loongarch_extioi-Add-virt-extension-support.patch similarity index 97% rename from 0030-hw-intc-loongarch_extioi-Add-virt-extension-support.patch rename to 0175-hw-intc-loongarch_extioi-Add-virt-extension-support.patch index eb41cbfa8dee4fdc0d82c6a01f7837df2e70d8fe..3ce3fa9f7bf95a2661b52a4720a50ead74d7c929 100644 --- a/0030-hw-intc-loongarch_extioi-Add-virt-extension-support.patch +++ b/0175-hw-intc-loongarch_extioi-Add-virt-extension-support.patch @@ -1,7 +1,7 @@ -From a13ffd86213dc98d8ed5bf255f3e0c61dd32aa08 Mon Sep 17 00:00:00 2001 +From c7c10a9c47c6403f9ae30dbd8c0f56d23de2980e Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Mon, 11 Mar 2024 15:01:31 +0800 -Subject: [PATCH] hw/intc/loongarch_extioi: Add virt extension support +Subject: [PATCH 185/293] hw/intc/loongarch_extioi: Add virt extension support With hardware extioi, irq can be routed to four vcpus with hardware extioi. This patch adds virt extension support, sot that irq can @@ -10,15 +10,15 @@ be routed to 256 vcpus. Signed-off-by: Song Gao Signed-off-by: Bibo Mao --- - hw/intc/loongarch_extioi.c | 98 ++++++++++++++++++++++++- - hw/loongarch/virt.c | 114 ++++++++++++++++++++++++++--- - include/hw/intc/loongarch_extioi.h | 22 +++++- + hw/intc/loongarch_extioi.c | 98 +++++++++++++++++++++++++++++-- + hw/loongarch/virt.c | 114 +++++++++++++++++++++++++++++++++---- + include/hw/intc/loongarch_extioi.h | 22 ++++++- include/hw/loongarch/virt.h | 3 + target/loongarch/cpu.h | 1 + 5 files changed, 221 insertions(+), 17 deletions(-) diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c -index bdfa3b481e..a892edcabb 100644 +index bdfa3b4..a892edc 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -55,6 +55,11 @@ static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level) @@ -184,7 +184,7 @@ index bdfa3b481e..a892edcabb 100644 dc->vmsd = &vmstate_loongarch_extioi; } diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c -index 6ef40fa24a..00359643a2 100644 +index 6ef40fa..0035964 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -15,6 +15,7 @@ @@ -361,7 +361,7 @@ index 6ef40fa24a..00359643a2 100644 static const TypeInfo loongarch_machine_types[] = { diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h -index a0a46b888c..3742fce3ee 100644 +index a0a46b8..3742fce 100644 --- a/include/hw/intc/loongarch_extioi.h +++ b/include/hw/intc/loongarch_extioi.h @@ -36,10 +36,27 @@ @@ -410,7 +410,7 @@ index a0a46b888c..3742fce3ee 100644 }; #endif /* LOONGARCH_EXTIOI_H */ diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h -index 252f7df7f4..d48aa579b2 100644 +index 252f7df..d48aa57 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -40,6 +40,7 @@ struct LoongArchMachineState { @@ -436,7 +436,7 @@ index 252f7df7f4..d48aa579b2 100644 #define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h -index 4aba8aba4c..4749d41c8c 100644 +index 4aba8ab..4749d41 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -36,6 +36,7 @@ @@ -448,5 +448,5 @@ index 4aba8aba4c..4749d41c8c 100644 #define IOCSR_MEM_SIZE 0x428 -- -2.33.0 +1.8.3.1 diff --git a/0031-target-loongarch-kvm-sync-kernel-header-files.patch b/0176-target-loongarch-kvm-sync-kernel-header-files.patch similarity index 86% rename from 0031-target-loongarch-kvm-sync-kernel-header-files.patch rename to 0176-target-loongarch-kvm-sync-kernel-header-files.patch index b276524c6d7ce7a7202336b28210fd6005520255..a8a3e031f523e28185b065a31fecd652bd288095 100644 --- a/0031-target-loongarch-kvm-sync-kernel-header-files.patch +++ b/0176-target-loongarch-kvm-sync-kernel-header-files.patch @@ -1,7 +1,7 @@ -From 1218acb3c23776861fa6b59d1eafc89aede8c246 Mon Sep 17 00:00:00 2001 +From 7e11828f4012fd0472184923a6b73b0f9eec534b Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 13 Mar 2024 10:04:33 +0800 -Subject: [PATCH] target/loongarch/kvm: sync kernel header files +Subject: [PATCH 186/293] target/loongarch/kvm: sync kernel header files sync kernel header files. @@ -11,7 +11,7 @@ Signed-off-by: Bibo Mao 1 file changed, 4 insertions(+) diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h -index 923d0bd382..4cec8c1601 100644 +index 923d0bd..4cec8c1 100644 --- a/linux-headers/asm-loongarch/kvm.h +++ b/linux-headers/asm-loongarch/kvm.h @@ -15,10 +15,12 @@ @@ -37,5 +37,5 @@ index 923d0bd382..4cec8c1601 100644 #define LOONGARCH_REG_SHIFT 3 #define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT)) -- -2.33.0 +1.8.3.1 diff --git a/0032-hw-intc-loongarch_extioi-Add-virt-extension-support-.patch b/0177-hw-intc-loongarch_extioi-Add-virt-extension-support-.patch similarity index 95% rename from 0032-hw-intc-loongarch_extioi-Add-virt-extension-support-.patch rename to 0177-hw-intc-loongarch_extioi-Add-virt-extension-support-.patch index 8a5884f44d7c1e0e5aff56a91a813e786d894f6c..c24944b2369064fb8b251368c56b0a7d06aae9aa 100644 --- a/0032-hw-intc-loongarch_extioi-Add-virt-extension-support-.patch +++ b/0177-hw-intc-loongarch_extioi-Add-virt-extension-support-.patch @@ -1,21 +1,22 @@ -From 93ea12e1570160c9048966a2a08a35cda2a2a6af Mon Sep 17 00:00:00 2001 +From c652cc1eb711edf00b7448c0eb8177bab80f0bea Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 13 Mar 2024 17:46:19 +0800 -Subject: [PATCH] hw/intc/loongarch_extioi: Add virt extension support v2 +Subject: [PATCH 187/293] hw/intc/loongarch_extioi: Add virt extension support + v2 fix 954c513fa3846f34ecd81e4eb25457ed49362b39 "Add virt extension support" in v2 version. Signed-off-by: Bibo Mao --- - hw/intc/loongarch_extioi.c | 24 ++++------- - hw/loongarch/virt.c | 64 +++++++++++++++++------------- + hw/intc/loongarch_extioi.c | 24 +++++--------- + hw/loongarch/virt.c | 64 +++++++++++++++++++++----------------- include/hw/intc/loongarch_extioi.h | 3 +- include/hw/loongarch/virt.h | 2 +- 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c -index a892edcabb..fa23e247ca 100644 +index a892edc..fa23e24 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -55,11 +55,6 @@ static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level) @@ -79,7 +80,7 @@ index a892edcabb..fa23e247ca 100644 static int vmstate_extioi_post_load(void *opaque, int version_id) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c -index 00359643a2..01e59f3a95 100644 +index 0035964..01e59f3 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -15,6 +15,7 @@ @@ -213,7 +214,7 @@ index 00359643a2..01e59f3a95 100644 static const TypeInfo loongarch_machine_types[] = { diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h -index 3742fce3ee..1cf5bf9922 100644 +index 3742fce..1cf5bf9 100644 --- a/include/hw/intc/loongarch_extioi.h +++ b/include/hw/intc/loongarch_extioi.h @@ -36,7 +36,7 @@ @@ -234,7 +235,7 @@ index 3742fce3ee..1cf5bf9922 100644 | BIT(EXTIOI_HAS_CPU_ENCODE)) #define EXTIOI_VIRT_CONFIG (0x4) diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h -index d48aa579b2..99447fd1d6 100644 +index d48aa57..99447fd 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -40,12 +40,12 @@ struct LoongArchMachineState { @@ -252,5 +253,5 @@ index d48aa579b2..99447fd1d6 100644 char *oem_table_id; DeviceState *acpi_ged; -- -2.33.0 +1.8.3.1 diff --git a/0178-target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch b/0178-target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch new file mode 100644 index 0000000000000000000000000000000000000000..d6273e9412c30a5fd07713657915f3a6bdf9b545 --- /dev/null +++ b/0178-target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch @@ -0,0 +1,230 @@ +From cd979dcfd9148e29e3603cf1473c1c27c98a10ee Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 14 Jun 2024 09:38:48 +0800 +Subject: [PATCH 188/293] target/loongarch/kvm: Implement LoongArch PMU + extension. + +Implement PMU extension for LoongArch kvm mode. Use OnOffAuto type +variable pmu to check the PMU feature. If the PMU Feature is not supported +with KVM host, it reports error if there is pmu=on command line. + +If there is no any command line about pmu parameter, it checks whether +KVM host supports the PMU Feature and set the corresponding value in cpucfg. + +Signed-off-by: Song Gao +Message-Id: <20240614013848.53474-1-gaosong@loongson.cn> +--- + linux-headers/asm-loongarch/kvm.h | 3 ++ + target/loongarch/cpu.c | 64 +++++++++++++++++++++++++++++++---- + target/loongarch/cpu.h | 6 ++++ + target/loongarch/kvm/kvm.c | 16 +++++++++ + target/loongarch/kvm/kvm_loongarch.h | 16 +++++++++ + target/loongarch/loongarch-qmp-cmds.c | 2 +- + 6 files changed, 99 insertions(+), 8 deletions(-) + +diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h +index 4cec8c1..b40b640 100644 +--- a/linux-headers/asm-loongarch/kvm.h ++++ b/linux-headers/asm-loongarch/kvm.h +@@ -85,6 +85,9 @@ struct kvm_fpu { + #define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG) + #define KVM_LOONGARCH_VCPU_CPUCFG 0 + ++#define KVM_LOONGARCH_VM_FEAT_CTRL 1000 ++#define KVM_LOONGARCH_VM_FEAT_PMU 1000 ++ + struct kvm_debug_exit_arch { + }; + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index b098b1c..17d9448 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -582,6 +582,35 @@ static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info) + info->print_insn = print_insn_loongarch; + } + ++static void loongarch_cpu_check_pmu(CPUState *cs, Error **errp) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(cs); ++ bool kvm_supported; ++ ++ kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PMU); ++ if (cpu->pmu == ON_OFF_AUTO_ON) { ++ if (kvm_supported) { ++ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, 1); ++ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMNUM, 3); ++ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMBITS, 63); ++ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, UPM, 1); ++ } else { ++ error_setg(errp, "'pmu' feature not supported by KVM on this host."); ++ return; ++ } ++ } else if ((cpu->pmu == ON_OFF_AUTO_AUTO) && kvm_supported) { ++ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, 1); ++ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMNUM, 3); ++ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMBITS, 63); ++ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, UPM, 1); ++ } ++} ++ ++static void loongarch_cpu_feature_realize(CPUState *cs, Error **errp) ++{ ++ loongarch_cpu_check_pmu(cs, errp); ++} ++ + static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) + { + CPUState *cs = CPU(dev); +@@ -595,6 +624,11 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) + } + + loongarch_cpu_register_gdb_regs_for_features(cs); ++ loongarch_cpu_feature_realize(cs, &local_err); ++ if (local_err != NULL) { ++ error_propagate(errp, local_err); ++ return; ++ } + + cpu_reset(cs); + qemu_init_vcpu(cs); +@@ -654,17 +688,33 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp) + } + } + ++static bool loongarch_get_pmu(Object *obj, Error **errp) ++{ ++ return LOONGARCH_CPU(obj)->pmu != ON_OFF_AUTO_OFF; ++} ++ ++static void loongarch_set_pmu(Object *obj, bool value, Error **errp) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(obj); ++ ++ cpu->pmu = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; ++} ++ + void loongarch_cpu_post_init(Object *obj) + { + LoongArchCPU *cpu = LOONGARCH_CPU(obj); + +- if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) { +- object_property_add_bool(obj, "lsx", loongarch_get_lsx, +- loongarch_set_lsx); +- } +- if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) { +- object_property_add_bool(obj, "lasx", loongarch_get_lasx, +- loongarch_set_lasx); ++ object_property_add_bool(obj, "lsx", loongarch_get_lsx, ++ loongarch_set_lsx); ++ object_property_add_bool(obj, "lasx", loongarch_get_lasx, ++ loongarch_set_lasx); ++ ++ if (kvm_enabled()) { ++ cpu->pmu = ON_OFF_AUTO_AUTO; ++ object_property_add_bool(obj, "pmu", loongarch_get_pmu, ++ loongarch_set_pmu); ++ } else { ++ cpu->pmu = ON_OFF_AUTO_OFF; + } + } + +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 4749d41..f07ed49 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -18,6 +18,7 @@ + #endif + #include "cpu-csr.h" + #include "cpu-qom.h" ++#include "qapi/qapi-types-common.h" + + #define IOCSRF_TEMP 0 + #define IOCSRF_NODECNT 1 +@@ -281,6 +282,10 @@ struct LoongArchTLB { + }; + typedef struct LoongArchTLB LoongArchTLB; + ++enum loongarch_features { ++ LOONGARCH_FEATURE_PMU, ++}; ++ + typedef struct CPUArchState { + uint64_t gpr[32]; + uint64_t pc; +@@ -377,6 +382,7 @@ struct ArchCPU { + CPULoongArchState env; + QEMUTimer timer; + uint32_t phy_id; ++ OnOffAuto pmu; + + /* 'compatible' string for this CPU for Linux device trees */ + const char *dtb_compatible; +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 49d0207..afcd917 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -874,6 +874,22 @@ int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level) + return kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); + } + ++bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature) ++{ ++ struct kvm_device_attr attr; ++ int ret; ++ ++ switch (feature) { ++ case LOONGARCH_FEATURE_PMU: ++ attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; ++ attr.attr = KVM_LOONGARCH_VM_FEAT_PMU; ++ ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); ++ return (ret == 0); ++ default: ++ return false; ++ } ++} ++ + void kvm_arch_accel_class_init(ObjectClass *oc) + { + } +diff --git a/target/loongarch/kvm/kvm_loongarch.h b/target/loongarch/kvm/kvm_loongarch.h +index d945b6b..bdb4f18 100644 +--- a/target/loongarch/kvm/kvm_loongarch.h ++++ b/target/loongarch/kvm/kvm_loongarch.h +@@ -13,4 +13,20 @@ + int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level); + void kvm_arch_reset_vcpu(CPULoongArchState *env); + ++#ifdef CONFIG_KVM ++/* ++ * kvm_feature_supported: ++ * ++ * Returns: true if KVM supports specified feature ++ * and false otherwise. ++ */ ++bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature); ++#else ++static inline bool kvm_feature_supported(CPUState *cs, ++ enum loongarch_features feature) ++{ ++ return false; ++} ++#endif ++ + #endif +diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c +index 645672f..de92ec6 100644 +--- a/target/loongarch/loongarch-qmp-cmds.c ++++ b/target/loongarch/loongarch-qmp-cmds.c +@@ -42,7 +42,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) + } + + static const char *cpu_model_advertised_features[] = { +- "lsx", "lasx", NULL ++ "lsx", "lasx", "pmu", NULL + }; + + CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, +-- +1.8.3.1 + diff --git a/0034-target-loongarch-Fix-qemu-system-loongarch64-assert-.patch b/0179-target-loongarch-Fix-qemu-system-loongarch64-assert-.patch similarity index 91% rename from 0034-target-loongarch-Fix-qemu-system-loongarch64-assert-.patch rename to 0179-target-loongarch-Fix-qemu-system-loongarch64-assert-.patch index 659cfc15369d7360af748f4a254050f5798205e3..75df19c95abfbed3c52d6cfda612fbb85e0645b5 100644 --- a/0034-target-loongarch-Fix-qemu-system-loongarch64-assert-.patch +++ b/0179-target-loongarch-Fix-qemu-system-loongarch64-assert-.patch @@ -1,7 +1,7 @@ -From 9e66722c617c4e01e2a5efdd7f533fd9d225033b Mon Sep 17 00:00:00 2001 +From fdb37262586c8838d7f7351dd824a48cd82dca64 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 2 Apr 2024 09:39:36 +0800 -Subject: [PATCH] target/loongarch: Fix qemu-system-loongarch64 assert +Subject: [PATCH 189/293] target/loongarch: Fix qemu-system-loongarch64 assert failed with the option '-d int' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -14,14 +14,14 @@ Signed-off-by: Song Gao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20240321123606.1704900-1-gaosong@loongson.cn> --- - target/loongarch/cpu.c | 74 +++++++++++++++++++++++------------------- + target/loongarch/cpu.c | 74 +++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c -index 86d18f89a4..bc557f207b 100644 +index 17d9448..c223712 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c -@@ -45,33 +45,45 @@ const char * const fregnames[32] = { +@@ -43,33 +43,45 @@ const char * const fregnames[32] = { "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; @@ -90,7 +90,7 @@ index 86d18f89a4..bc557f207b 100644 } void G_NORETURN do_raise_exception(CPULoongArchState *env, -@@ -80,7 +92,7 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env, +@@ -78,7 +90,7 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env, { CPUState *cs = env_cpu(env); @@ -99,7 +99,7 @@ index 86d18f89a4..bc557f207b 100644 __func__, exception, loongarch_exception_name(exception)); -@@ -161,22 +173,16 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) +@@ -159,22 +171,16 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) CPULoongArchState *env = &cpu->env; bool update_badinstr = 1; int cause = -1; @@ -127,5 +127,5 @@ index 86d18f89a4..bc557f207b 100644 switch (cs->exception_index) { -- -2.33.0 +1.8.3.1 diff --git a/0036-target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch b/0180-target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch similarity index 88% rename from 0036-target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch rename to 0180-target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch index 70007479a596fb4717c73715e816350fd398b8e7..6ff6f1b8a1c7ea32584e4a985d9a88f320199425 100644 --- a/0036-target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch +++ b/0180-target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch @@ -1,7 +1,8 @@ -From d93c003720daea0d50dd6bfacce3e01dec6fd6ba Mon Sep 17 00:00:00 2001 +From aedd1399a605898177af4bc4675450c9ada23296 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Wed, 8 May 2024 10:47:32 +0800 -Subject: [PATCH] target/loongarch/kvm: Fix VM recovery from disk failures +Subject: [PATCH 190/293] target/loongarch/kvm: Fix VM recovery from disk + failures vmstate does not save kvm_state_conter, which can cause VM recovery from disk to fail. @@ -14,7 +15,7 @@ Message-Id: <20240508024732.3127792-1-gaosong@loongson.cn> 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c -index 1c4e01d076..5a7df713e2 100644 +index 1c4e01d..5a7df71 100644 --- a/target/loongarch/machine.c +++ b/target/loongarch/machine.c @@ -125,8 +125,8 @@ const VMStateDescription vmstate_tlb = { @@ -38,5 +39,5 @@ index 1c4e01d076..5a7df713e2 100644 }, .subsections = (const VMStateDescription*[]) { -- -2.33.0 +1.8.3.1 diff --git a/0037-target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch b/0181-target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch similarity index 79% rename from 0037-target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch rename to 0181-target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch index 085408481c00a05b8383ab702e4adcdeb71eb862..7d3555fa2fd5b95e5020f83ae3008d67f90f5f0a 100644 --- a/0037-target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch +++ b/0181-target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch @@ -1,8 +1,8 @@ -From acc4c06ed8e754f73974bddc39a877f6b5dea867 Mon Sep 17 00:00:00 2001 +From 30220a25e28fd7faa80825fcdcafecdc3128a88f Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 14 May 2024 19:07:52 +0800 -Subject: [PATCH 2/2] target/loongarch/kvm: fpu save the vreg registers high - 192bit +Subject: [PATCH 191/293] target/loongarch/kvm: fpu save the vreg registers + high 192bit On kvm side, get_fpu/set_fpu save the vreg registers high 192bits, but QEMU missing. @@ -15,10 +15,10 @@ Message-Id: <20240514110752.989572-1-gaosong@loongson.cn> 1 file changed, 6 insertions(+) diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c -index bc75552d0f..8e6e27c8bf 100644 +index afcd917..3306cb5 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c -@@ -436,6 +436,9 @@ static int kvm_loongarch_get_regs_fp(CPUState *cs) +@@ -444,6 +444,9 @@ static int kvm_loongarch_get_regs_fp(CPUState *cs) env->fcsr0 = fpu.fcsr; for (i = 0; i < 32; i++) { env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0]; @@ -28,7 +28,7 @@ index bc75552d0f..8e6e27c8bf 100644 } for (i = 0; i < 8; i++) { env->cf[i] = fpu.fcc & 0xFF; -@@ -455,6 +458,9 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs) +@@ -465,6 +468,9 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs) fpu.fcc = 0; for (i = 0; i < 32; i++) { fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0]; @@ -39,5 +39,5 @@ index bc75552d0f..8e6e27c8bf 100644 for (i = 0; i < 8; i++) { -- -2.34.1 +1.8.3.1 diff --git a/0182-target-i386-add-support-for-LAM-in-CPUID-enumeration.patch b/0182-target-i386-add-support-for-LAM-in-CPUID-enumeration.patch new file mode 100644 index 0000000000000000000000000000000000000000..81d71de690b64a5de9ac60c5dde8572c6653c168 --- /dev/null +++ b/0182-target-i386-add-support-for-LAM-in-CPUID-enumeration.patch @@ -0,0 +1,69 @@ +From 420c8697531bf3ab2bd799c62a4a072b4c8668fe Mon Sep 17 00:00:00 2001 +From: Robert Hoo +Date: Fri, 12 Jan 2024 14:00:41 +0800 +Subject: [PATCH 192/293] target/i386: add support for LAM in CPUID enumeration + +commit ba6780905943696d790cc880c8e5684b51f027fe upstream. + +Linear Address Masking (LAM) is a new Intel CPU feature, which allows +software to use of the untranslated address bits for metadata. + +The bit definition: +CPUID.(EAX=7,ECX=1):EAX[26] + +Add CPUID definition for LAM. + +Note LAM feature is not supported for TCG of target-i386, LAM CPIUD bit +will not be added to TCG_7_1_EAX_FEATURES. + +More info can be found in Intel ISE Chapter "LINEAR ADDRESS MASKING(LAM)" +https://cdrdv2.intel.com/v1/dl/getContent/671368 + +Intel-SIG: commit ba6780905943 target/i386: add support for LAM in CPUID +enumeration +Backport Qemu Linear Address Masking (LAM) support. + +Signed-off-by: Robert Hoo +Co-developed-by: Binbin Wu +Signed-off-by: Binbin Wu +Tested-by: Xuelian Guo +Reviewed-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Message-ID: <20240112060042.19925-2-binbin.wu@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Zhiquan Li: amend commit log ] +Signed-off-by: Zhiquan Li +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 5c0dfee..b031d5b 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -967,7 +967,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + "fsrc", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, "amx-fp16", NULL, "avx-ifma", +- NULL, NULL, NULL, NULL, ++ NULL, NULL, "lam", NULL, + NULL, NULL, NULL, NULL, + }, + .cpuid = { +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 705d925..d361f83 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -925,6 +925,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_AMX_FP16 (1U << 21) + /* Support for VPMADD52[H,L]UQ */ + #define CPUID_7_1_EAX_AVX_IFMA (1U << 23) ++/* Linear Address Masking */ ++#define CPUID_7_1_EAX_LAM (1U << 26) + + /* Support for VPDPB[SU,UU,SS]D[,S] */ + #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) +-- +1.8.3.1 + diff --git a/0183-target-i386-add-control-bits-support-for-LAM.patch b/0183-target-i386-add-control-bits-support-for-LAM.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c1d0cf6c3228e2b27d1315025dcc9119abc744e --- /dev/null +++ b/0183-target-i386-add-control-bits-support-for-LAM.patch @@ -0,0 +1,99 @@ +From aabf8b96bfbacd88b0fbe833078acf248be69b1d Mon Sep 17 00:00:00 2001 +From: Binbin Wu +Date: Fri, 12 Jan 2024 14:00:42 +0800 +Subject: [PATCH 193/293] target/i386: add control bits support for LAM + +commit 0117067131f99acaab4f4d2cca0290c5510e37cf upstream. + +LAM uses CR3[61] and CR3[62] to configure/enable LAM on user pointers. +LAM uses CR4[28] to configure/enable LAM on supervisor pointers. + +For CR3 LAM bits, no additional handling needed: +- TCG + LAM is not supported for TCG of target-i386. helper_write_crN() and + helper_vmrun() check max physical address bits before calling + cpu_x86_update_cr3(), no change needed, i.e. CR3 LAM bits are not allowed + to be set in TCG. +- gdbstub + x86_cpu_gdb_write_register() will call cpu_x86_update_cr3() to update cr3. + Allow gdb to set the LAM bit(s) to CR3, if vcpu doesn't support LAM, + KVM_SET_SREGS will fail as other reserved bits. + +For CR4 LAM bit, its reservation depends on vcpu supporting LAM feature or +not. +- TCG + LAM is not supported for TCG of target-i386. helper_write_crN() and + helper_vmrun() check CR4 reserved bit before calling cpu_x86_update_cr4(), + i.e. CR4 LAM bit is not allowed to be set in TCG. +- gdbstub + x86_cpu_gdb_write_register() will call cpu_x86_update_cr4() to update cr4. + Mask out LAM bit on CR4 if vcpu doesn't support LAM. +- x86_cpu_reset_hold() doesn't need special handling. + +Intel-SIG: commit 0117067131f9 target/i386: add control bits support for +LAM +Backport Qemu Linear Address Masking (LAM) support. + +Signed-off-by: Binbin Wu +Tested-by: Xuelian Guo +Reviewed-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Message-ID: <20240112060042.19925-3-binbin.wu@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Zhiquan Li: amend commit log ] +Signed-off-by: Zhiquan Li +--- + target/i386/cpu.h | 7 ++++++- + target/i386/helper.c | 4 ++++ + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index d361f83..2e166a7 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -261,6 +261,7 @@ typedef enum X86Seg { + #define CR4_SMAP_MASK (1U << 21) + #define CR4_PKE_MASK (1U << 22) + #define CR4_PKS_MASK (1U << 24) ++#define CR4_LAM_SUP_MASK (1U << 28) + + #define CR4_RESERVED_MASK \ + (~(target_ulong)(CR4_VME_MASK | CR4_PVI_MASK | CR4_TSD_MASK \ +@@ -269,7 +270,8 @@ typedef enum X86Seg { + | CR4_OSFXSR_MASK | CR4_OSXMMEXCPT_MASK | CR4_UMIP_MASK \ + | CR4_LA57_MASK \ + | CR4_FSGSBASE_MASK | CR4_PCIDE_MASK | CR4_OSXSAVE_MASK \ +- | CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_PKE_MASK | CR4_PKS_MASK)) ++ | CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_PKE_MASK | CR4_PKS_MASK \ ++ | CR4_LAM_SUP_MASK)) + + #define DR6_BD (1 << 13) + #define DR6_BS (1 << 14) +@@ -2527,6 +2529,9 @@ static inline uint64_t cr4_reserved_bits(CPUX86State *env) + if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKS)) { + reserved_bits |= CR4_PKS_MASK; + } ++ if (!(env->features[FEAT_7_1_EAX] & CPUID_7_1_EAX_LAM)) { ++ reserved_bits |= CR4_LAM_SUP_MASK; ++ } + return reserved_bits; + } + +diff --git a/target/i386/helper.c b/target/i386/helper.c +index 2070dd0..1da7a7d 100644 +--- a/target/i386/helper.c ++++ b/target/i386/helper.c +@@ -219,6 +219,10 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) + new_cr4 &= ~CR4_PKS_MASK; + } + ++ if (!(env->features[FEAT_7_1_EAX] & CPUID_7_1_EAX_LAM)) { ++ new_cr4 &= ~CR4_LAM_SUP_MASK; ++ } ++ + env->cr[4] = new_cr4; + env->hflags = hflags; + +-- +1.8.3.1 + diff --git a/0184-target-i386-Introduce-Icelake-Server-v7-to-enable-TS.patch b/0184-target-i386-Introduce-Icelake-Server-v7-to-enable-TS.patch new file mode 100644 index 0000000000000000000000000000000000000000..e3b565c98393009556165c43f0d08164bd3a95c9 --- /dev/null +++ b/0184-target-i386-Introduce-Icelake-Server-v7-to-enable-TS.patch @@ -0,0 +1,65 @@ +From 80a505605d6bf3d27e224650394b4465ca7f15af Mon Sep 17 00:00:00 2001 +From: Zhenzhong Duan +Date: Wed, 20 Mar 2024 17:31:38 +0800 +Subject: [PATCH 194/293] target/i386: Introduce Icelake-Server-v7 to enable + TSX + +commit c895fa54e3060c5ac6f3888dce96c9b78626072b upstream. + +When start L2 guest with both L1/L2 using Icelake-Server-v3 or above, +QEMU reports below warning: + +"warning: host doesn't support requested feature: MSR(10AH).taa-no [bit 8]" + +Reason is QEMU Icelake-Server-v3 has TSX feature disabled but enables taa-no +bit. It's meaningless that TSX isn't supported but still claim TSX is secure. +So L1 KVM doesn't expose taa-no to L2 if TSX is unsupported, then starting L2 +triggers the warning. + +Fix it by introducing a new version Icelake-Server-v7 which has both TSX +and taa-no features. Then guest can use TSX securely when it see taa-no. + +This matches the production Icelake which supports TSX and isn't susceptible +to TSX Async Abort (TAA) vulnerabilities, a.k.a, taa-no. + +Ideally, TSX should have being enabled together with taa-no since v3, but for +compatibility, we'd better to add v7 to enable it. + +Fixes: d965dc35592d ("target/i386: Add ARCH_CAPABILITIES related bits into Icelake-Server CPU model") + +Intel-SIG: commit c895fa54e306 target/i386: Introduce Icelake-Server-v7 to enable TSX. + +Tested-by: Xiangfei Ma +Signed-off-by: Zhenzhong Duan +Message-ID: <20240320093138.80267-2-zhenzhong.duan@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index b031d5b..ffa2dae 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -3822,6 +3822,16 @@ static const X86CPUDefinition builtin_x86_defs[] = { + { /* end of list */ } + }, + }, ++ { ++ .version = 7, ++ .note = "TSX, taa-no", ++ .props = (PropValue[]) { ++ /* Restore TSX features removed by -v2 above */ ++ { "hle", "on" }, ++ { "rtm", "on" }, ++ { /* end of list */ } ++ }, ++ }, + { /* end of list */ } + } + }, +-- +1.8.3.1 + diff --git a/0185-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch b/0185-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch new file mode 100644 index 0000000000000000000000000000000000000000..1ea8fb6c8aa82016fdfbcb08380405086483be19 --- /dev/null +++ b/0185-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch @@ -0,0 +1,47 @@ +From f7cccf45b1de006f68f22fb0c9062324119504ed Mon Sep 17 00:00:00 2001 +From: Lei Wang +Date: Wed, 24 Apr 2024 03:29:12 -0400 +Subject: [PATCH 195/293] target/i386: Introduce SapphireRapids-v3 to add + missing features + +commit b10b2481738304db13d28252e86c10555121a5b3 upstream. + +Add the missing features(ss, tsc-adjust, cldemote, movdiri, movdir64b) in +the SapphireRapids-v3 CPU model. + +Intel-SIG: commit b10b24817383 target/i386: Introduce SapphireRapids-v3 to add missing features + +Signed-off-by: Lei Wang +Message-ID: <20240424072912.43188-1-lei4.wang@intel.com> +Signed-off-by: Paolo Bonzini +[jz: amend commit log] +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index ffa2dae..f764e82 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -3970,6 +3970,17 @@ static const X86CPUDefinition builtin_x86_defs[] = { + { /* end of list */ } + } + }, ++ { ++ .version = 3, ++ .props = (PropValue[]) { ++ { "ss", "on" }, ++ { "tsc-adjust", "on" }, ++ { "cldemote", "on" }, ++ { "movdiri", "on" }, ++ { "movdir64b", "on" }, ++ { /* end of list */ } ++ } ++ }, + { /* end of list */ } + } + }, +-- +1.8.3.1 + diff --git a/0186-target-i386-add-guest-phys-bits-cpu-property.patch b/0186-target-i386-add-guest-phys-bits-cpu-property.patch new file mode 100644 index 0000000000000000000000000000000000000000..e9dcbf778979d2275307703ee7049f2ac9d1263c --- /dev/null +++ b/0186-target-i386-add-guest-phys-bits-cpu-property.patch @@ -0,0 +1,106 @@ +From 882f1ee12dd7e54cbe5116d3eba72f43f1a49631 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 18 Mar 2024 16:53:36 +0100 +Subject: [PATCH 196/293] target/i386: add guest-phys-bits cpu property + +commit 513ba32dccc659c80722b3a43233b26eaa50309a upstream. + +Allows to set guest-phys-bits (cpuid leaf 80000008, eax[23:16]) +via -cpu $model,guest-phys-bits=$nr. + +Intel-SIG: commit 513ba32dccc6 target/i386: add guest-phys-bits cpu property + +Signed-off-by: Gerd Hoffmann +Message-ID: <20240318155336.156197-3-kraxel@redhat.com> +Reviewed-by: Zhao Liu +Signed-off-by: Paolo Bonzini +[jz: compatible property for 9.0 machines not included] +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 22 ++++++++++++++++++++++ + target/i386/cpu.h | 8 ++++++++ + 2 files changed, 30 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index f764e82..ffdaf16 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6713,6 +6713,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { + /* 64 bit processor */ + *eax |= (cpu_x86_virtual_addr_width(env) << 8); ++ *eax |= (cpu->guest_phys_bits << 16); + } + *ebx = env->features[FEAT_8000_0008_EBX]; + if (cs->nr_cores * cs->nr_threads > 1) { +@@ -7467,6 +7468,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + goto out; + } + ++ if (cpu->guest_phys_bits == -1) { ++ /* ++ * If it was not set by the user, or by the accelerator via ++ * cpu_exec_realizefn, clear. ++ */ ++ cpu->guest_phys_bits = 0; ++ } ++ + if (cpu->ucode_rev == 0) { + /* + * The default is the same as KVM's. Note that this check +@@ -7517,6 +7526,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + if (cpu->phys_bits == 0) { + cpu->phys_bits = TCG_PHYS_ADDR_BITS; + } ++ if (cpu->guest_phys_bits && ++ (cpu->guest_phys_bits > cpu->phys_bits || ++ cpu->guest_phys_bits < 32)) { ++ error_setg(errp, "guest-phys-bits should be between 32 and %u " ++ " (but is %u)", ++ cpu->phys_bits, cpu->guest_phys_bits); ++ return; ++ } + } else { + /* For 32 bit systems don't use the user set value, but keep + * phys_bits consistent with what we tell the guest. +@@ -7525,6 +7542,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + error_setg(errp, "phys-bits is not user-configurable in 32 bit"); + return; + } ++ if (cpu->guest_phys_bits != 0) { ++ error_setg(errp, "guest-phys-bits is not user-configurable in 32 bit"); ++ return; ++ } + + if (env->features[FEAT_1_EDX] & (CPUID_PSE36 | CPUID_PAE)) { + cpu->phys_bits = 36; +@@ -8013,6 +8034,7 @@ static Property x86_cpu_properties[] = { + DEFINE_PROP_BOOL("x-force-features", X86CPU, force_features, false), + DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), + DEFINE_PROP_UINT32("phys-bits", X86CPU, phys_bits, 0), ++ DEFINE_PROP_UINT32("guest-phys-bits", X86CPU, guest_phys_bits, -1), + DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false), + DEFINE_PROP_UINT8("host-phys-bits-limit", X86CPU, host_phys_bits_limit, 0), + DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true), +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 2e166a7..877fc2b 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -2023,6 +2023,14 @@ struct ArchCPU { + /* Number of physical address bits supported */ + uint32_t phys_bits; + ++ /* ++ * Number of guest physical address bits available. Usually this is ++ * identical to host physical address bits. With NPT or EPT 4-level ++ * paging, guest physical address space might be restricted to 48 bits ++ * even if the host cpu supports more physical address bits. ++ */ ++ uint32_t guest_phys_bits; ++ + /* in order to simplify APIC support, we leave this pointer to the + user */ + struct DeviceState *apic_state; +-- +1.8.3.1 + diff --git a/0187-kvm-add-support-for-guest-physical-bits.patch b/0187-kvm-add-support-for-guest-physical-bits.patch new file mode 100644 index 0000000000000000000000000000000000000000..29a78423eed1b3ce47517a237898736a9af95c28 --- /dev/null +++ b/0187-kvm-add-support-for-guest-physical-bits.patch @@ -0,0 +1,112 @@ +From aebdb4506a35e9ebfd7a86ed8b86466772285100 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 18 Mar 2024 16:53:35 +0100 +Subject: [PATCH 197/293] kvm: add support for guest physical bits + +commit 0d08c423688edcca857f88dab20f1fc56de2b281 upstream. + +Query kvm for supported guest physical address bits, in cpuid +function 80000008, eax[23:16]. Usually this is identical to host +physical address bits. With NPT or EPT being used this might be +restricted to 48 (max 4-level paging address space size) even if +the host cpu supports more physical address bits. + +When set pass this to the guest, using cpuid too. Guest firmware +can use this to figure how big the usable guest physical address +space is, so PCI bar mapping are actually reachable. + +Intel-SIG: commit 0d08c423688e kvm: add support for guest physical bits + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Message-ID: <20240318155336.156197-2-kraxel@redhat.com> +Signed-off-by: Paolo Bonzini +[jz: amend commit log] +Signed-off-by: Jason Zeng +--- + target/i386/kvm/kvm-cpu.c | 50 +++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 42 insertions(+), 8 deletions(-) + +diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c +index 9c791b7..f76972e 100644 +--- a/target/i386/kvm/kvm-cpu.c ++++ b/target/i386/kvm/kvm-cpu.c +@@ -18,10 +18,32 @@ + #include "kvm_i386.h" + #include "hw/core/accel-cpu.h" + ++static void kvm_set_guest_phys_bits(CPUState *cs) ++{ ++ X86CPU *cpu = X86_CPU(cs); ++ uint32_t eax, guest_phys_bits; ++ ++ eax = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x80000008, 0, R_EAX); ++ guest_phys_bits = (eax >> 16) & 0xff; ++ if (!guest_phys_bits) { ++ return; ++ } ++ cpu->guest_phys_bits = guest_phys_bits; ++ if (cpu->guest_phys_bits > cpu->phys_bits) { ++ cpu->guest_phys_bits = cpu->phys_bits; ++ } ++ ++ if (cpu->host_phys_bits && cpu->host_phys_bits_limit && ++ cpu->guest_phys_bits > cpu->host_phys_bits_limit) { ++ cpu->guest_phys_bits = cpu->host_phys_bits_limit; ++ } ++} ++ + static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) + { + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; ++ bool ret; + + /* + * The realize order is important, since x86_cpu_realize() checks if +@@ -32,13 +54,15 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) + * + * realize order: + * +- * x86_cpu_realize(): +- * -> x86_cpu_expand_features() +- * -> cpu_exec_realizefn(): +- * -> accel_cpu_common_realize() +- * kvm_cpu_realizefn() -> host_cpu_realizefn() +- * -> cpu_common_realizefn() +- * -> check/update ucode_rev, phys_bits, mwait ++ * x86_cpu_realizefn(): ++ * x86_cpu_expand_features() ++ * cpu_exec_realizefn(): ++ * accel_cpu_common_realize() ++ * kvm_cpu_realizefn() ++ * host_cpu_realizefn() ++ * kvm_set_guest_phys_bits() ++ * check/update ucode_rev, phys_bits, guest_phys_bits, mwait ++ * cpu_common_realizefn() (via xcc->parent_realize) + */ + if (cpu->max_features) { + if (enable_cpu_pm && kvm_has_waitpkg()) { +@@ -50,7 +74,17 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) + MSR_IA32_UCODE_REV); + } + } +- return host_cpu_realizefn(cs, errp); ++ ret = host_cpu_realizefn(cs, errp); ++ if (!ret) { ++ return ret; ++ } ++ ++ if ((env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) && ++ cpu->guest_phys_bits == -1) { ++ kvm_set_guest_phys_bits(cs); ++ } ++ ++ return true; + } + + static bool lmce_supported(void) +-- +1.8.3.1 + diff --git a/0035-newfeature-support-vpsp.patch b/0188-support-vpsp.patch similarity index 95% rename from 0035-newfeature-support-vpsp.patch rename to 0188-support-vpsp.patch index 05a4bd6e1e9a0e3e78679a68df5a1b4e1714a033..63aa59878d43d4535092d82f042aecc5d01544f3 100644 --- a/0035-newfeature-support-vpsp.patch +++ b/0188-support-vpsp.patch @@ -1,7 +1,7 @@ -From 445b34648510cfae60fa52311199dcf9e6b3c24d Mon Sep 17 00:00:00 2001 +From 5c688679ed8afe0082e2770439a6e10fff04ee75 Mon Sep 17 00:00:00 2001 From: xiongmengbiao Date: Thu, 30 Nov 2023 13:47:21 +0800 -Subject: [PATCH] [newfeature]: support vpsp +Subject: [PATCH 198/293] support vpsp simulate a psp misc device for support tkm's key isolation @@ -10,12 +10,12 @@ Signed-off-by: xiongmengbiao --- hw/misc/Kconfig | 4 ++ hw/misc/meson.build | 1 + - hw/misc/psp.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ + hw/misc/psp.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 hw/misc/psp.c diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig -index cc8a8c1418..2ea5c68eb5 100644 +index cc8a8c1..2ea5c68 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -200,4 +200,8 @@ config IOSB @@ -28,7 +28,7 @@ index cc8a8c1418..2ea5c68eb5 100644 + source macio/Kconfig diff --git a/hw/misc/meson.build b/hw/misc/meson.build -index 36c20d5637..28cba0ac28 100644 +index 36c20d5..28cba0a 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -9,6 +9,7 @@ system_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c')) @@ -41,7 +41,7 @@ index 36c20d5637..28cba0ac28 100644 system_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c')) diff --git a/hw/misc/psp.c b/hw/misc/psp.c new file mode 100644 -index 0000000000..1cfbab859e +index 0000000..da0a69e --- /dev/null +++ b/hw/misc/psp.c @@ -0,0 +1,141 @@ @@ -187,5 +187,5 @@ index 0000000000..1cfbab859e + +type_init(psp_dev_register_types) -- -2.41.0 +1.8.3.1 diff --git a/1005-doc-update-AMD-SEV-to-include-Live-migration-flow.patch b/0189-doc-update-AMD-SEV-to-include-Live-migration-flow.patch similarity index 93% rename from 1005-doc-update-AMD-SEV-to-include-Live-migration-flow.patch rename to 0189-doc-update-AMD-SEV-to-include-Live-migration-flow.patch index d1e845a87415cfb8c7a1eb3798e0a43e282969ee..abfef166f95abe4fcd582a771b0ece3ffddc6943 100644 --- a/1005-doc-update-AMD-SEV-to-include-Live-migration-flow.patch +++ b/0189-doc-update-AMD-SEV-to-include-Live-migration-flow.patch @@ -1,7 +1,7 @@ -From 7baee92cb9227cf83903bc022ce486c962201638 Mon Sep 17 00:00:00 2001 +From ff30577f3ebef6b2e57c31909e0a87fa96f43a46 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Thu, 7 May 2020 22:26:17 +0000 -Subject: [PATCH 01/28] doc: update AMD SEV to include Live migration flow +Subject: [PATCH 199/293] doc: update AMD SEV to include Live migration flow cherry-picked from https://github.com/AMDESE/qemu/commit/0e2b3d80e3. @@ -10,11 +10,11 @@ Signed-off-by: Brijesh Singh Signed-off-by: Ashish Kalra Signed-off-by: hanliyang --- - docs/system/i386/amd-memory-encryption.rst | 40 +++++++++++++++++++++- + docs/system/i386/amd-memory-encryption.rst | 40 +++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/docs/system/i386/amd-memory-encryption.rst b/docs/system/i386/amd-memory-encryption.rst -index e9bc142bc..b7e3f46ff 100644 +index e9bc142..b7e3f46 100644 --- a/docs/system/i386/amd-memory-encryption.rst +++ b/docs/system/i386/amd-memory-encryption.rst @@ -177,7 +177,45 @@ TODO @@ -65,5 +65,5 @@ index e9bc142bc..b7e3f46ff 100644 References ---------- -- -2.31.1 +1.8.3.1 diff --git a/1006-migration.json-add-AMD-SEV-specific-migration-parame.patch b/0190-migration.json-add-AMD-SEV-specific-migration-parame.patch similarity index 96% rename from 1006-migration.json-add-AMD-SEV-specific-migration-parame.patch rename to 0190-migration.json-add-AMD-SEV-specific-migration-parame.patch index 4963898a116bad0c2da1f3de1336e3c4a843e4f8..4ca77fceab90aad88722d5ca77484156c434e56d 100644 --- a/1006-migration.json-add-AMD-SEV-specific-migration-parame.patch +++ b/0190-migration.json-add-AMD-SEV-specific-migration-parame.patch @@ -1,7 +1,7 @@ -From e9999946bd358b88ff4c8c66306c1cbf09fda189 Mon Sep 17 00:00:00 2001 +From 0499615720dea35526bd7ef18449240f8cdfe630 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 27 Jul 2021 11:27:00 +0000 -Subject: [PATCH 02/28] migration.json: add AMD SEV specific migration +Subject: [PATCH 200/293] migration.json: add AMD SEV specific migration parameters cherry-picked from https://github.com/AMDESE/qemu/commit/d6a23bde6b6e. @@ -17,13 +17,13 @@ Signed-off-by: Ashish Kalra [ Fix conflicts and qapi errors. ] Signed-off-by: hanliyang --- - migration/migration-hmp-cmds.c | 28 ++++++++++++++++ - migration/options.c | 60 ++++++++++++++++++++++++++++++++++ - qapi/migration.json | 41 +++++++++++++++++++++-- + migration/migration-hmp-cmds.c | 28 ++++++++++++++++++++ + migration/options.c | 60 ++++++++++++++++++++++++++++++++++++++++++ + qapi/migration.json | 41 ++++++++++++++++++++++++++--- 3 files changed, 126 insertions(+), 3 deletions(-) diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c -index 86ae83217..7e83d908d 100644 +index 2faa5ca..58da696 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -392,6 +392,19 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) @@ -69,7 +69,7 @@ index 86ae83217..7e83d908d 100644 assert(0); } diff --git a/migration/options.c b/migration/options.c -index 8d8ec73ad..70f6beb83 100644 +index 8d8ec73..70f6beb 100644 --- a/migration/options.c +++ b/migration/options.c @@ -179,6 +179,9 @@ Property migration_properties[] = { @@ -175,7 +175,7 @@ index 8d8ec73ad..70f6beb83 100644 migrate_params_test_apply(params, &tmp); diff --git a/qapi/migration.json b/qapi/migration.json -index eb2f88351..77051496f 100644 +index 197d3fa..d9b25ef 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -874,6 +874,15 @@ @@ -262,5 +262,5 @@ index eb2f88351..77051496f 100644 ## # @query-migrate-parameters: -- -2.31.1 +1.8.3.1 diff --git a/1007-confidential-guest-support-introduce-ConfidentialGue.patch b/0191-confidential-guest-support-introduce-ConfidentialGue.patch similarity index 93% rename from 1007-confidential-guest-support-introduce-ConfidentialGue.patch rename to 0191-confidential-guest-support-introduce-ConfidentialGue.patch index 359e1e34de5ac04afc48f54b370155bfb1749105..f6b6f4dbb4629e11576f881f56a1e674497d187b 100644 --- a/1007-confidential-guest-support-introduce-ConfidentialGue.patch +++ b/0191-confidential-guest-support-introduce-ConfidentialGue.patch @@ -1,7 +1,7 @@ -From f667d5c3e315ea85a2d83da2384d24fe74c2aa0b Mon Sep 17 00:00:00 2001 +From dacd8c4764e41e0b8e6fe46fe29f9e65ca1f5625 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 27 Jul 2021 11:41:37 +0000 -Subject: [PATCH 03/28] confidential guest support: introduce +Subject: [PATCH 201/293] confidential guest support: introduce ConfidentialGuestMemoryEncryptionOps for encrypted VMs cherry-picked from https://github.com/AMDESE/qemu/commit/74fce7be9bd. @@ -19,11 +19,11 @@ Co-developed-by: Ashish Kalra Signed-off-by: Ashish Kalra Signed-off-by: hanliyang --- - include/exec/confidential-guest-support.h | 27 +++++++++++++++++++++++ + include/exec/confidential-guest-support.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index ba2dd4b5d..343f686fc 100644 +index ba2dd4b..343f686 100644 --- a/include/exec/confidential-guest-support.h +++ b/include/exec/confidential-guest-support.h @@ -53,8 +53,35 @@ struct ConfidentialGuestSupport { @@ -63,5 +63,5 @@ index ba2dd4b5d..343f686fc 100644 #endif /* !CONFIG_USER_ONLY */ -- -2.31.1 +1.8.3.1 diff --git a/1008-target-i386-sev-provide-callback-to-setup-outgoing-c.patch b/0192-target-i386-sev-provide-callback-to-setup-outgoing-c.patch similarity index 94% rename from 1008-target-i386-sev-provide-callback-to-setup-outgoing-c.patch rename to 0192-target-i386-sev-provide-callback-to-setup-outgoing-c.patch index 3aab1b3b9ed6ba633c62269eda03773af27dd2df..e7db25aeda98b8d741c64040e5478484a590b238 100644 --- a/1008-target-i386-sev-provide-callback-to-setup-outgoing-c.patch +++ b/0192-target-i386-sev-provide-callback-to-setup-outgoing-c.patch @@ -1,7 +1,7 @@ -From 07d01bcf6ca2a3e5fb369f7a25b954aaebbc9b5e Mon Sep 17 00:00:00 2001 +From dbd192392ad43804584938db8179f5861940dcd4 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 27 Jul 2021 12:10:23 +0000 -Subject: [PATCH 04/28] target/i386: sev: provide callback to setup outgoing +Subject: [PATCH 202/293] target/i386: sev: provide callback to setup outgoing context cherry-picked from https://github.com/AMDESE/qemu/commit/7521883afc0. @@ -16,12 +16,12 @@ Signed-off-by: Ashish Kalra [ Fix conflict. ] Signed-off-by: hanliyang --- - target/i386/sev.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ + target/i386/sev.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ target/i386/sev.h | 2 ++ 2 files changed, 61 insertions(+) diff --git a/target/i386/sev.c b/target/i386/sev.c -index 9a7124668..3ab02f4c6 100644 +index 9a71246..3ab02f4 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -73,6 +73,12 @@ struct SevGuestState { @@ -119,7 +119,7 @@ index 9a7124668..3ab02f4c6 100644 return 0; diff --git a/target/i386/sev.h b/target/i386/sev.h -index e7499c95b..e96de021f 100644 +index e7499c9..e96de02 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -51,6 +51,8 @@ uint32_t sev_get_reduced_phys_bits(void); @@ -132,5 +132,5 @@ index e7499c95b..e96de021f 100644 uint64_t gpa, Error **errp); -- -2.31.1 +1.8.3.1 diff --git a/1009-target-i386-sev-do-not-create-launch-context-for-an-.patch b/0193-target-i386-sev-do-not-create-launch-context-for-an-.patch similarity index 88% rename from 1009-target-i386-sev-do-not-create-launch-context-for-an-.patch rename to 0193-target-i386-sev-do-not-create-launch-context-for-an-.patch index 4dcd6f3d4465fa6368ba75aab4439a82ed205034..680f23e5a9056acddf1a96730e7de2d245d92e3c 100644 --- a/1009-target-i386-sev-do-not-create-launch-context-for-an-.patch +++ b/0193-target-i386-sev-do-not-create-launch-context-for-an-.patch @@ -1,7 +1,7 @@ -From 66ccff57037c3fd1a24554111447137b6525c764 Mon Sep 17 00:00:00 2001 +From 85eccfb010be99335ab4465fff0504dd2f7acc09 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 27 Jul 2021 12:16:09 +0000 -Subject: [PATCH 05/28] target/i386: sev: do not create launch context for an +Subject: [PATCH 203/293] target/i386: sev: do not create launch context for an incoming guest cherry-picked from https://github.com/AMDESE/qemu/commit/b85694233495. @@ -20,7 +20,7 @@ Signed-off-by: hanliyang 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c -index 3ab02f4c6..b56cbdb6b 100644 +index 3ab02f4..b56cbdb 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -1060,10 +1060,16 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) @@ -45,5 +45,5 @@ index 3ab02f4c6..b56cbdb6b 100644 ram_block_notifier_add(&sev_ram_notifier); -- -2.31.1 +1.8.3.1 diff --git a/1010-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch b/0194-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch similarity index 97% rename from 1010-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch rename to 0194-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch index c23a01161937d9006506a4be4b0370716e7976f5..1a9bf60419b044d9fe1fd8533300eca763c34d75 100644 --- a/1010-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch +++ b/0194-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch @@ -1,7 +1,7 @@ -From 8d08dc0a8622eb8c512d96a1720c0e52a8ffc5ac Mon Sep 17 00:00:00 2001 +From 32124419dfb142e6c0d23b8a7917ce8566a4160b Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 27 Jul 2021 12:55:25 +0000 -Subject: [PATCH 06/28] target/i386: sev: add support to encrypt the outgoing +Subject: [PATCH 204/293] target/i386: sev: add support to encrypt the outgoing page cherry-picked from https://github.com/AMDESE/qemu/commit/5187c6f86bd. @@ -21,13 +21,13 @@ Signed-off-by: Ashish Kalra [ Fix conflict. ] Signed-off-by: hanliyang --- - target/i386/sev.c | 219 +++++++++++++++++++++++++++++++++++++++ + target/i386/sev.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++ target/i386/sev.h | 2 + target/i386/trace-events | 3 + 3 files changed, 224 insertions(+) diff --git a/target/i386/sev.c b/target/i386/sev.c -index b56cbdb6b..617587c69 100644 +index b56cbdb..617587c 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -31,6 +31,8 @@ @@ -292,7 +292,7 @@ index b56cbdb6b..617587c69 100644 .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21) diff --git a/target/i386/sev.h b/target/i386/sev.h -index e96de021f..463e94bb8 100644 +index e96de02..463e94b 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -53,6 +53,8 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp); @@ -305,7 +305,7 @@ index e96de021f..463e94bb8 100644 uint64_t gpa, Error **errp); diff --git a/target/i386/trace-events b/target/i386/trace-events -index 2cd8726ee..e8d4aec12 100644 +index 2cd8726..e8d4aec 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -11,3 +11,6 @@ kvm_sev_launch_measurement(const char *value) "data %s" @@ -316,5 +316,5 @@ index 2cd8726ee..e8d4aec12 100644 +kvm_sev_send_update_data(void *src, void *dst, int len) "guest %p trans %p len %d" +kvm_sev_send_finish(void) "" -- -2.31.1 +1.8.3.1 diff --git a/1011-target-i386-sev-add-support-to-load-incoming-encrypt.patch b/0195-target-i386-sev-add-support-to-load-incoming-encrypt.patch similarity index 96% rename from 1011-target-i386-sev-add-support-to-load-incoming-encrypt.patch rename to 0195-target-i386-sev-add-support-to-load-incoming-encrypt.patch index 98c5e1f52faffb715359b1e1649f3df3e112dde8..785a1b1e0e38f98d299a956507c2e9e6a85dfca3 100644 --- a/1011-target-i386-sev-add-support-to-load-incoming-encrypt.patch +++ b/0195-target-i386-sev-add-support-to-load-incoming-encrypt.patch @@ -1,7 +1,7 @@ -From 0016dedce755380dc796e605f68c40d1c1b2edad Mon Sep 17 00:00:00 2001 +From 814f0c308cf71dcd076f23e9fe554c2b5f56c5bf Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 27 Jul 2021 13:00:50 +0000 -Subject: [PATCH 07/28] target/i386: sev: add support to load incoming +Subject: [PATCH 205/293] target/i386: sev: add support to load incoming encrypted page cherry-picked from https://github.com/AMDESE/qemu/commit/e86e5dccb045. @@ -21,13 +21,13 @@ Signed-off-by: Ashish Kalra [ Fix conflicts. ] Signed-off-by: hanliyang --- - target/i386/sev.c | 137 ++++++++++++++++++++++++++++++++++++++- + target/i386/sev.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++- target/i386/sev.h | 1 + - target/i386/trace-events | 3 + + target/i386/trace-events | 3 ++ 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/target/i386/sev.c b/target/i386/sev.c -index 617587c69..ee42edf4e 100644 +index 617587c..ee42edf 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -172,6 +172,7 @@ static const char *const sev_fw_errlist[] = { @@ -195,7 +195,7 @@ index 617587c69..ee42edf4e 100644 .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21) diff --git a/target/i386/sev.h b/target/i386/sev.h -index 463e94bb8..d94da2956 100644 +index 463e94b..d94da29 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -55,6 +55,7 @@ int sev_save_setup(const char *pdh, const char *plat_cert, @@ -207,7 +207,7 @@ index 463e94bb8..d94da2956 100644 uint64_t gpa, Error **errp); diff --git a/target/i386/trace-events b/target/i386/trace-events -index e8d4aec12..475de65ad 100644 +index e8d4aec..475de65 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -14,3 +14,6 @@ kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data @@ -218,5 +218,5 @@ index e8d4aec12..475de65ad 100644 +kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_len) "guest %p trans %p len %d hdr %p hdr_len %d" +kvm_sev_receive_finish(void) "" -- -2.31.1 +1.8.3.1 diff --git a/1012-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch b/0196-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch similarity index 95% rename from 1012-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch rename to 0196-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch index 069445af359cd597e9061664e1b94c1671e9afcf..70d7c77184cfe217f5eba7ee5518628d2bb7e7e6 100644 --- a/1012-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch +++ b/0196-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch @@ -1,7 +1,7 @@ -From 08a6f74fec36c0a8af0fa4a8d32186222617d95e Mon Sep 17 00:00:00 2001 +From 493ec7bb50b5020429809cacdbcbad1c5b2f5b65 Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Tue, 27 Jul 2021 15:05:49 +0000 -Subject: [PATCH 08/28] kvm: Add support for SEV shared regions list and +Subject: [PATCH 206/293] kvm: Add support for SEV shared regions list and KVM_EXIT_HYPERCALL. cherry-picked from https://github.com/AMDESE/qemu/commit/fcbbd9b19ac. @@ -25,14 +25,14 @@ Signed-off-by: Ashish Kalra Signed-off-by: hanliyang --- linux-headers/linux/kvm.h | 3 ++ - target/i386/kvm/kvm.c | 48 +++++++++++++++++ - target/i386/kvm/sev-stub.c | 11 ++++ - target/i386/sev.c | 106 +++++++++++++++++++++++++++++++++++++ + target/i386/kvm/kvm.c | 48 ++++++++++++++++++++ + target/i386/kvm/sev-stub.c | 11 +++++ + target/i386/sev.c | 106 +++++++++++++++++++++++++++++++++++++++++++++ target/i386/sev.h | 3 ++ 5 files changed, 171 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 549fea3a9..9758e8fec 100644 +index 549fea3..9758e8f 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -346,6 +346,7 @@ struct kvm_run { @@ -53,7 +53,7 @@ index 549fea3a9..9758e8fec 100644 struct kvm_irq_routing_irqchip { diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index a0bc9ea7b..82f6d3b04 100644 +index a0bc9ea..82f6d3b 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -148,6 +148,7 @@ static int has_xcrs; @@ -140,7 +140,7 @@ index a0bc9ea7b..82f6d3b04 100644 fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); ret = -1; diff --git a/target/i386/kvm/sev-stub.c b/target/i386/kvm/sev-stub.c -index 1be5341e8..1282d242a 100644 +index 1be5341..1282d24 100644 --- a/target/i386/kvm/sev-stub.c +++ b/target/i386/kvm/sev-stub.c @@ -19,3 +19,14 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) @@ -159,7 +159,7 @@ index 1be5341e8..1282d242a 100644 + return 0; +} diff --git a/target/i386/sev.c b/target/i386/sev.c -index ee42edf4e..bd00a28e9 100644 +index ee42edf..bd00a28 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -44,6 +44,11 @@ @@ -297,7 +297,7 @@ index ee42edf4e..bd00a28e9 100644 .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21) diff --git a/target/i386/sev.h b/target/i386/sev.h -index d94da2956..acf69d4e6 100644 +index d94da29..acf69d4 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -61,6 +61,9 @@ int sev_inject_launch_secret(const char *hdr, const char *secret, @@ -311,5 +311,5 @@ index d94da2956..acf69d4e6 100644 int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); -- -2.31.1 +1.8.3.1 diff --git a/1013-migration-add-support-to-migrate-shared-regions-list.patch b/0197-migration-add-support-to-migrate-shared-regions-list.patch similarity index 93% rename from 1013-migration-add-support-to-migrate-shared-regions-list.patch rename to 0197-migration-add-support-to-migrate-shared-regions-list.patch index e0633d752648eaa2cd190aaa26e5e79815e36590..b14d8ceee8d6029b3866413d1560916bde17e016 100644 --- a/1013-migration-add-support-to-migrate-shared-regions-list.patch +++ b/0197-migration-add-support-to-migrate-shared-regions-list.patch @@ -1,7 +1,7 @@ -From 458a857abe8ba6dd8e581957dba850c36277f92f Mon Sep 17 00:00:00 2001 +From 54a29f988c761e7da755da938b52f96d2662a99f Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 27 Jul 2021 16:31:36 +0000 -Subject: [PATCH 09/28] migration: add support to migrate shared regions list +Subject: [PATCH 207/293] migration: add support to migrate shared regions list cherry-picked from https://github.com/AMDESE/qemu/commit/9236f522e48b6. @@ -18,12 +18,12 @@ Signed-off-by: Ashish Kalra Signed-off-by: hanliyang --- include/exec/confidential-guest-support.h | 2 +- - target/i386/sev.c | 45 +++++++++++++++++++++++ - target/i386/sev.h | 2 + + target/i386/sev.c | 45 +++++++++++++++++++++++++++++++ + target/i386/sev.h | 2 ++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 343f686fc..dd4887f65 100644 +index 343f686..dd4887f 100644 --- a/include/exec/confidential-guest-support.h +++ b/include/exec/confidential-guest-support.h @@ -73,7 +73,7 @@ struct ConfidentialGuestMemoryEncryptionOps { @@ -36,7 +36,7 @@ index 343f686fc..dd4887f65 100644 /* Load the shared regions list */ int (*load_incoming_shared_regions_list)(QEMUFile *f); diff --git a/target/i386/sev.c b/target/i386/sev.c -index bd00a28e9..aeb3e323d 100644 +index bd00a28..aeb3e32 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -176,10 +176,15 @@ static const char *const sev_fw_errlist[] = { @@ -103,7 +103,7 @@ index bd00a28e9..aeb3e323d 100644 .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21) diff --git a/target/i386/sev.h b/target/i386/sev.h -index acf69d4e6..5b4231c85 100644 +index acf69d4..5b4231c 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -64,6 +64,8 @@ void sev_es_set_reset_vector(CPUState *cpu); @@ -116,5 +116,5 @@ index acf69d4e6..5b4231c85 100644 int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); -- -2.31.1 +1.8.3.1 diff --git a/1014-migration-ram-add-support-to-send-encrypted-pages.patch b/0198-migration-ram-add-support-to-send-encrypted-pages.patch similarity index 95% rename from 1014-migration-ram-add-support-to-send-encrypted-pages.patch rename to 0198-migration-ram-add-support-to-send-encrypted-pages.patch index fbc7295be7fc6add7d37294fce3f23823fe29a45..d3e682d557b156e7e2331eff244d6ce977c41ea6 100644 --- a/1014-migration-ram-add-support-to-send-encrypted-pages.patch +++ b/0198-migration-ram-add-support-to-send-encrypted-pages.patch @@ -1,7 +1,7 @@ -From 639f32076d0a6596ebd0fbc7aa6465786c57e5e8 Mon Sep 17 00:00:00 2001 +From 2b93c1ead8fdf9730e6d2ea5799bac409c87825c Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 27 Jul 2021 16:53:19 +0000 -Subject: [PATCH 10/28] migration/ram: add support to send encrypted pages +Subject: [PATCH 208/293] migration/ram: add support to send encrypted pages cherry-picked from https://github.com/AMDESE/qemu/commit/2d6bda0d4cf. @@ -20,13 +20,13 @@ Signed-off-by: Ashish Kalra Signed-off-by: hanliyang --- migration/migration.h | 2 + - migration/ram.c | 174 +++++++++++++++++++++++++++++++++++++++++- + migration/ram.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++- target/i386/sev.c | 14 ++++ - target/i386/sev.h | 4 + + target/i386/sev.h | 4 ++ 4 files changed, 192 insertions(+), 2 deletions(-) diff --git a/migration/migration.h b/migration/migration.h -index cf2c9c88e..65f5599f4 100644 +index cf2c9c8..65f5599 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -550,4 +550,6 @@ void migration_rp_kick(MigrationState *s); @@ -37,7 +37,7 @@ index cf2c9c88e..65f5599f4 100644 + #endif diff --git a/migration/ram.c b/migration/ram.c -index 8c7886ab7..317aea563 100644 +index 8c7886a..317aea5 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -63,6 +63,10 @@ @@ -69,11 +69,10 @@ index 8c7886ab7..317aea563 100644 XBZRLECacheStats xbzrle_counters; -@@ -1204,6 +1217,88 @@ static int save_normal_page(PageSearchStatus *pss, RAMBlock *block, - return 1; +@@ -1205,6 +1218,88 @@ static int save_normal_page(PageSearchStatus *pss, RAMBlock *block, } -+/** + /** + * ram_save_encrypted_page - send the given encrypted page to the stream + */ +static int ram_save_encrypted_page(RAMState *rs, PageSearchStatus *pss) @@ -155,14 +154,14 @@ index 8c7886ab7..317aea563 100644 + } +} + - /** ++/** * ram_save_page: send the given page to the stream * -@@ -2034,6 +2129,35 @@ static bool save_compress_page(RAMState *rs, PageSearchStatus *pss, - compress_send_queued_data); + * Returns the number of pages written. +@@ -2035,6 +2130,35 @@ static bool save_compress_page(RAMState *rs, PageSearchStatus *pss, } -+/** + /** + * encrypted_test_list: check if the page is encrypted + * + * Returns a bool indicating whether the page is encrypted. @@ -191,9 +190,10 @@ index 8c7886ab7..317aea563 100644 + return ops->is_gfn_in_unshared_region(gfn); +} + - /** ++/** * ram_save_target_page_legacy: save one target page * + * Returns the number of pages written @@ -2052,6 +2176,17 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss) return res; } @@ -285,7 +285,7 @@ index 8c7886ab7..317aea563 100644 error_report("Unknown combination of migration flags: 0x%x", flags); ret = -EINVAL; diff --git a/target/i386/sev.c b/target/i386/sev.c -index aeb3e323d..851175631 100644 +index aeb3e32..8511756 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -183,6 +183,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { @@ -317,7 +317,7 @@ index aeb3e323d..851175631 100644 .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21) diff --git a/target/i386/sev.h b/target/i386/sev.h -index 5b4231c85..b9c2afb79 100644 +index 5b4231c..b9c2afb 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -38,6 +38,9 @@ typedef struct SevKernelLoaderContext { @@ -339,5 +339,5 @@ index 5b4231c85..b9c2afb79 100644 int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); -- -2.31.1 +1.8.3.1 diff --git a/1015-migration-ram-Force-encrypted-status-for-flash0-flas.patch b/0199-migration-ram-Force-encrypted-status-for-flash0-flas.patch similarity index 88% rename from 1015-migration-ram-Force-encrypted-status-for-flash0-flas.patch rename to 0199-migration-ram-Force-encrypted-status-for-flash0-flas.patch index 22cb91cb0648dec9c2535c0a225e411ec31c6d1e..f71a1a631f3d8ca6bcd48ccb28b88826e45f66e6 100644 --- a/1015-migration-ram-Force-encrypted-status-for-flash0-flas.patch +++ b/0199-migration-ram-Force-encrypted-status-for-flash0-flas.patch @@ -1,7 +1,7 @@ -From d92cc48c799a42a8aaccc4e21ce95213981bef00 Mon Sep 17 00:00:00 2001 +From 388bb911357c1cf7d2b03e31bebe9670e3139408 Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Tue, 27 Jul 2021 18:05:25 +0000 -Subject: [PATCH 11/28] migration/ram: Force encrypted status for flash0 & +Subject: [PATCH 209/293] migration/ram: Force encrypted status for flash0 & flash1 devices. cherry-picked from https://github.com/AMDESE/qemu/commit/803d6a4c8d. @@ -21,7 +21,7 @@ Signed-off-by: hanliyang 1 file changed, 8 insertions(+) diff --git a/migration/ram.c b/migration/ram.c -index 317aea563..09faa8572 100644 +index 317aea5..09faa85 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2149,6 +2149,14 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, @@ -40,5 +40,5 @@ index 317aea563..09faa8572 100644 * Translate page in ram_addr_t address space to GPA address * space using memory region. -- -2.31.1 +1.8.3.1 diff --git a/1016-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch b/0200-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch similarity index 92% rename from 1016-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch rename to 0200-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch index 455ad292a96b3a6f05dbc608769538f562896782..e78204a999b02fae68db7f0fb133b67986f516d5 100644 --- a/1016-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch +++ b/0200-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch @@ -1,7 +1,7 @@ -From fadc1e0f1a90a7e81da7eca4604ef2733070d022 Mon Sep 17 00:00:00 2001 +From bfa2537c9ae8d8db06cb6fd585a556b2104b4c4d Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Tue, 27 Jul 2021 17:59:33 +0000 -Subject: [PATCH 12/28] kvm: Add support for userspace MSR filtering and +Subject: [PATCH 210/293] kvm: Add support for userspace MSR filtering and handling of MSR_KVM_MIGRATION_CONTROL. cherry-picked from https://github.com/AMDESE/qemu/commit/67935c3fd5f. @@ -25,7 +25,7 @@ Signed-off-by: hanliyang 4 files changed, 46 insertions(+) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 82f6d3b04..a5a755db0 100644 +index 82f6d3b..a5a755d 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -2488,6 +2488,32 @@ static bool kvm_rdmsr_core_thread_count(X86CPU *cpu, uint32_t msr, @@ -78,7 +78,7 @@ index 82f6d3b04..a5a755db0 100644 return 0; diff --git a/target/i386/kvm/sev-stub.c b/target/i386/kvm/sev-stub.c -index 1282d242a..99899688e 100644 +index 1282d24..9989968 100644 --- a/target/i386/kvm/sev-stub.c +++ b/target/i386/kvm/sev-stub.c @@ -30,3 +30,7 @@ int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end) @@ -90,7 +90,7 @@ index 1282d242a..99899688e 100644 +{ +} diff --git a/target/i386/sev.c b/target/i386/sev.c -index 851175631..aeeb479b5 100644 +index 8511756..aeeb479 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -925,6 +925,12 @@ sev_launch_finish(SevGuestState *sev) @@ -107,7 +107,7 @@ index 851175631..aeeb479b5 100644 sev_receive_finish(SevGuestState *s) { diff --git a/target/i386/sev.h b/target/i386/sev.h -index b9c2afb79..84e3bdf2d 100644 +index b9c2afb..84e3bdf 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -70,6 +70,7 @@ int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); @@ -119,5 +119,5 @@ index b9c2afb79..84e3bdf2d 100644 int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); -- -2.31.1 +1.8.3.1 diff --git a/1017-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch b/0201-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch similarity index 89% rename from 1017-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch rename to 0201-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch index 675caa3cb160f84bb6e50b8b00b7580fb5462650..dc9d8048e4c4c51d52ec0b30e4750c702dbb41bd 100644 --- a/1017-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch +++ b/0201-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch @@ -1,8 +1,8 @@ -From 73ea7fc6bb73f32c95328c540361d2ea1671fdc2 Mon Sep 17 00:00:00 2001 +From ddc1237fe7657246829340cca45f855030cb7159 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Wed, 31 Jan 2024 07:26:57 +0800 -Subject: [PATCH 13/28] target/i386: sev: Return 0 if sev_send_get_packet_len() - fails +Subject: [PATCH 211/293] target/i386: sev: Return 0 if + sev_send_get_packet_len() fails The send_packet_hdr_len of struct SEVState is of type size_t which is an unsigned class type. If the send_packet_hdr_len @@ -43,7 +43,7 @@ Signed-off-by: hanliyang 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/sev.c b/target/i386/sev.c -index aeeb479b5..b1b26b8a2 100644 +index aeeb479..b1b26b8 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -1491,7 +1491,7 @@ sev_send_get_packet_len(int *fw_err) @@ -56,5 +56,5 @@ index aeeb479b5..b1b26b8a2 100644 __func__, ret, *fw_err, fw_error_to_str(*fw_err)); goto err; -- -2.31.1 +1.8.3.1 diff --git a/1018-migration-ram-Force-encrypted-status-for-VGA-vram.patch b/0202-migration-ram-Force-encrypted-status-for-VGA-vram.patch similarity index 81% rename from 1018-migration-ram-Force-encrypted-status-for-VGA-vram.patch rename to 0202-migration-ram-Force-encrypted-status-for-VGA-vram.patch index c986ca2b73b86957ba991757cb26ebe678fb9e3b..64b489f847af680ba4be9725223a3238465c9b5f 100644 --- a/1018-migration-ram-Force-encrypted-status-for-VGA-vram.patch +++ b/0202-migration-ram-Force-encrypted-status-for-VGA-vram.patch @@ -1,7 +1,7 @@ -From e0cf323893b47b5184f6a87354c6eec3f1e0a1c2 Mon Sep 17 00:00:00 2001 +From 478d0a924da5e32ba7b707c98798f25d66e80c42 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Tue, 8 Dec 2020 22:57:46 -0500 -Subject: [PATCH 14/28] migration/ram: Force encrypted status for VGA vram +Subject: [PATCH 212/293] migration/ram: Force encrypted status for VGA vram The VGA vram memory region act as frame buffer of VM. This memory is decrypted in the QEMU process. For CSV VM live migration, we @@ -13,7 +13,7 @@ Signed-off-by: hanliyang 1 file changed, 4 insertions(+) diff --git a/migration/ram.c b/migration/ram.c -index 09faa8572..f71173855 100644 +index 09faa85..f711738 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2157,6 +2157,10 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, @@ -28,5 +28,5 @@ index 09faa8572..f71173855 100644 * Translate page in ram_addr_t address space to GPA address * space using memory region. -- -2.31.1 +1.8.3.1 diff --git a/1019-target-i386-sev-Clear-shared_regions_list-when-reboo.patch b/0203-target-i386-sev-Clear-shared_regions_list-when-reboo.patch similarity index 88% rename from 1019-target-i386-sev-Clear-shared_regions_list-when-reboo.patch rename to 0203-target-i386-sev-Clear-shared_regions_list-when-reboo.patch index 26140d3783010b99869bb2c848a80473962ebd9e..960299866a771932dd278b8f754c763f2a0cfd64 100644 --- a/1019-target-i386-sev-Clear-shared_regions_list-when-reboo.patch +++ b/0203-target-i386-sev-Clear-shared_regions_list-when-reboo.patch @@ -1,8 +1,8 @@ -From 64925eb013b2b0c85f2dd2a791019eebfb1e195f Mon Sep 17 00:00:00 2001 +From 1a43356669c8b2e2b8d0b7168d3f9cddc84cac9a Mon Sep 17 00:00:00 2001 From: hanliyang Date: Sun, 16 Jan 2022 19:57:58 -0500 -Subject: [PATCH 15/28] target/i386: sev: Clear shared_regions_list when reboot - CSV Guest +Subject: [PATCH 213/293] target/i386: sev: Clear shared_regions_list when + reboot CSV Guest Also fix memory leak in sev_remove_shared_regions_list(). @@ -13,7 +13,7 @@ Signed-off-by: hanliyang 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index a5a755db0..5730d0e0c 100644 +index a5a755d..5730d0e 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -2270,6 +2270,11 @@ void kvm_arch_reset_vcpu(X86CPU *cpu) @@ -29,7 +29,7 @@ index a5a755db0..5730d0e0c 100644 env->poll_control_msr = 1; diff --git a/target/i386/sev.c b/target/i386/sev.c -index b1b26b8a2..594f034e8 100644 +index b1b26b8..594f034 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -1693,9 +1693,9 @@ int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr) @@ -53,5 +53,5 @@ index b1b26b8a2..594f034e8 100644 pos->gfn_start = r; } else if (r == pos->gfn_end) { -- -2.31.1 +1.8.3.1 diff --git a/1020-migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch b/0204-migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch similarity index 90% rename from 1020-migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch rename to 0204-migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch index bd35406a3f49a8a6a17f75a2073fbf83d7911878..2dbeb7699dbc4e1cf06fc4023dd41edcce709b32 100644 --- a/1020-migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch +++ b/0204-migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch @@ -1,7 +1,7 @@ -From e5107cd74257898fd2a1bf83883e4142c652980e Mon Sep 17 00:00:00 2001 +From 982df892d3b3896a8379447bc8b85ce84d733a1f Mon Sep 17 00:00:00 2001 From: hanliyang Date: Sun, 16 Jan 2022 20:05:02 -0500 -Subject: [PATCH 16/28] migration/ram: Fix calculation of gfn correpond to a +Subject: [PATCH 214/293] migration/ram: Fix calculation of gfn correpond to a page in ramblock A RAMBlock contains a host memory region which may consist of many @@ -16,7 +16,7 @@ Signed-off-by: hanliyang 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/migration/ram.c b/migration/ram.c -index f71173855..22f07a064 100644 +index f711738..22f07a0 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -67,6 +67,7 @@ @@ -53,5 +53,5 @@ index f71173855..22f07a064 100644 return ops->is_gfn_in_unshared_region(gfn); } -- -2.31.1 +1.8.3.1 diff --git a/1021-target-i386-Introduce-header-file-csv.h.patch b/0205-target-i386-Introduce-header-file-csv.h.patch similarity index 88% rename from 1021-target-i386-Introduce-header-file-csv.h.patch rename to 0205-target-i386-Introduce-header-file-csv.h.patch index 7bd9203a856654bf4c71d82032b0d5c4b8ea2f00..88ff1531940facb90c3c69cc0f83e616a4c5e9a7 100644 --- a/1021-target-i386-Introduce-header-file-csv.h.patch +++ b/0205-target-i386-Introduce-header-file-csv.h.patch @@ -1,7 +1,7 @@ -From 1a911e312fc82eedd8200ef28a7f8fed1ffe4aec Mon Sep 17 00:00:00 2001 +From 576385738a1c163c11acba84594178ee47383fdd Mon Sep 17 00:00:00 2001 From: hanliyang Date: Thu, 14 Mar 2024 19:21:11 +0800 -Subject: [PATCH 17/28] target/i386: Introduce header file csv.h +Subject: [PATCH 215/293] target/i386: Introduce header file csv.h This header file is used to provide common helper functions and data structures for Hygon CSV. @@ -9,13 +9,13 @@ and data structures for Hygon CSV. Signed-off-by: hanliyang --- configs/devices/i386-softmmu/default.mak | 1 + - hw/i386/Kconfig | 5 +++ - target/i386/csv.h | 47 ++++++++++++++++++++++++ + hw/i386/Kconfig | 5 ++++ + target/i386/csv.h | 47 ++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 target/i386/csv.h diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak -index 598c6646d..db83ffcab 100644 +index 598c664..db83ffc 100644 --- a/configs/devices/i386-softmmu/default.mak +++ b/configs/devices/i386-softmmu/default.mak @@ -23,6 +23,7 @@ @@ -27,7 +27,7 @@ index 598c6646d..db83ffcab 100644 # Boards: # diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig -index 55850791d..08f3ae43f 100644 +index 5585079..08f3ae4 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -10,6 +10,10 @@ config SGX @@ -51,7 +51,7 @@ index 55850791d..08f3ae43f 100644 imply TPM_TIS_ISA diff --git a/target/i386/csv.h b/target/i386/csv.h new file mode 100644 -index 000000000..f935babe9 +index 0000000..f935bab --- /dev/null +++ b/target/i386/csv.h @@ -0,0 +1,47 @@ @@ -103,5 +103,5 @@ index 000000000..f935babe9 + +#endif -- -2.31.1 +1.8.3.1 diff --git a/1022-target-i386-csv-Read-cert-chain-from-file-when-prepa.patch b/0206-target-i386-csv-Read-cert-chain-from-file-when-prepa.patch similarity index 95% rename from 1022-target-i386-csv-Read-cert-chain-from-file-when-prepa.patch rename to 0206-target-i386-csv-Read-cert-chain-from-file-when-prepa.patch index bac67afcb3805870135c043bdf000c3843bb9ced..ef456de02fa6d652c54e3c0381103ba63bfb3cea 100644 --- a/1022-target-i386-csv-Read-cert-chain-from-file-when-prepa.patch +++ b/0206-target-i386-csv-Read-cert-chain-from-file-when-prepa.patch @@ -1,7 +1,7 @@ -From 771f30ba4ab5be48a2d88499fb7a3b5072536587 Mon Sep 17 00:00:00 2001 +From 6cd1b91414784f2651c279814663e30d9b028e57 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Mon, 13 Nov 2023 21:55:33 +0000 -Subject: [PATCH 18/28] target/i386: csv: Read cert chain from file when +Subject: [PATCH 216/293] target/i386: csv: Read cert chain from file when prepared for CSV live migration The cert chain is too long when encoded with base64, use the filename @@ -16,7 +16,7 @@ Signed-off-by: hanliyang 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/qapi/migration.json b/qapi/migration.json -index 77051496f..14e70a5b7 100644 +index d9b25ef..3c4724d 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -874,14 +874,16 @@ @@ -80,7 +80,7 @@ index 77051496f..14e70a5b7 100644 # Features: # diff --git a/target/i386/sev.c b/target/i386/sev.c -index 594f034e8..ab7893fca 100644 +index 594f034..ab7893f 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -27,6 +27,7 @@ @@ -136,5 +136,5 @@ index 594f034e8..ab7893fca 100644 goto error; } -- -2.31.1 +1.8.3.1 diff --git a/1023-target-i386-csv-add-support-to-queue-the-outgoing-pa.patch b/0207-target-i386-csv-add-support-to-queue-the-outgoing-pa.patch similarity index 95% rename from 1023-target-i386-csv-add-support-to-queue-the-outgoing-pa.patch rename to 0207-target-i386-csv-add-support-to-queue-the-outgoing-pa.patch index 8737896cbc941e7a9b5784b8ce68485f05b06f15..bd0122c2a925e26c92bd094ce826c5626bbff872 100644 --- a/1023-target-i386-csv-add-support-to-queue-the-outgoing-pa.patch +++ b/0207-target-i386-csv-add-support-to-queue-the-outgoing-pa.patch @@ -1,7 +1,7 @@ -From 80508ddb448151afabbab70d34178d07fb1a2bdf Mon Sep 17 00:00:00 2001 +From 459ef550486fbf7211707bda276a348a9711e0da Mon Sep 17 00:00:00 2001 From: fangbaoshun Date: Mon, 2 Aug 2021 11:00:07 +0800 -Subject: [PATCH 19/28] target/i386: csv: add support to queue the outgoing +Subject: [PATCH 217/293] target/i386: csv: add support to queue the outgoing page into a list The csv_queue_outgoing_page() provide the implementation to queue the @@ -12,13 +12,13 @@ encrypt the pages togather before writing them to the socket. Signed-off-by: hanliyang --- include/exec/confidential-guest-support.h | 3 + - linux-headers/linux/kvm.h | 6 + + linux-headers/linux/kvm.h | 6 ++ target/i386/csv.h | 11 ++ - target/i386/sev.c | 161 ++++++++++++++++++++++ + target/i386/sev.c | 161 ++++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+) diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index dd4887f65..8949568ac 100644 +index dd4887f..8949568 100644 --- a/include/exec/confidential-guest-support.h +++ b/include/exec/confidential-guest-support.h @@ -77,6 +77,9 @@ struct ConfidentialGuestMemoryEncryptionOps { @@ -32,7 +32,7 @@ index dd4887f65..8949568ac 100644 typedef struct ConfidentialGuestSupportClass { diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 9758e8fec..a61be972c 100644 +index 9758e8f..a61be97 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -2024,6 +2024,12 @@ struct kvm_sev_receive_update_data { @@ -49,7 +49,7 @@ index 9758e8fec..a61be972c 100644 #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) diff --git a/target/i386/csv.h b/target/i386/csv.h -index f935babe9..4c1ef2002 100644 +index f935bab..4c1ef20 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -44,4 +44,15 @@ static bool __attribute__((unused)) is_hygon_cpu(void) @@ -69,7 +69,7 @@ index f935babe9..4c1ef2002 100644 + #endif diff --git a/target/i386/sev.c b/target/i386/sev.c -index ab7893fca..027249e44 100644 +index ab7893f..027249e 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -95,6 +95,9 @@ struct SevGuestState { @@ -255,5 +255,5 @@ index ab7893fca..027249e44 100644 .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21) -- -2.31.1 +1.8.3.1 diff --git a/1024-target-i386-csv-add-support-to-encrypt-the-outgoing-.patch b/0208-target-i386-csv-add-support-to-encrypt-the-outgoing-.patch similarity index 94% rename from 1024-target-i386-csv-add-support-to-encrypt-the-outgoing-.patch rename to 0208-target-i386-csv-add-support-to-encrypt-the-outgoing-.patch index 8e53350fcacb33cd6b5c3dc2e645456cd4f93bd1..344ebe0019a14ad4464e2c715561295168a58899 100644 --- a/1024-target-i386-csv-add-support-to-encrypt-the-outgoing-.patch +++ b/0208-target-i386-csv-add-support-to-encrypt-the-outgoing-.patch @@ -1,7 +1,7 @@ -From 95ec49aa8a1a291f2fbb34daf9b054307161ab3f Mon Sep 17 00:00:00 2001 +From 98a84342005697d79cdf1edbff23ed12ae857f05 Mon Sep 17 00:00:00 2001 From: fangbaoshun Date: Mon, 2 Aug 2021 11:41:58 +0800 -Subject: [PATCH 20/28] target/i386: csv: add support to encrypt the outgoing +Subject: [PATCH 218/293] target/i386: csv: add support to encrypt the outgoing pages in the list queued before. The csv_save_queued_outgoing_pages() provide the implementation to encrypt @@ -19,12 +19,12 @@ Signed-off-by: hanliyang include/exec/confidential-guest-support.h | 4 ++ linux-headers/linux/kvm.h | 8 +++ target/i386/csv.h | 1 + - target/i386/sev.c | 88 +++++++++++++++++++++++ - target/i386/sev.h | 3 + + target/i386/sev.c | 88 +++++++++++++++++++++++++++++++ + target/i386/sev.h | 3 ++ 5 files changed, 104 insertions(+) diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 8949568ac..c84f8c1ef 100644 +index 8949568..c84f8c1 100644 --- a/include/exec/confidential-guest-support.h +++ b/include/exec/confidential-guest-support.h @@ -80,6 +80,10 @@ struct ConfidentialGuestMemoryEncryptionOps { @@ -39,7 +39,7 @@ index 8949568ac..c84f8c1ef 100644 typedef struct ConfidentialGuestSupportClass { diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index a61be972c..8595dd5ca 100644 +index a61be97..8595dd5 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1928,6 +1928,9 @@ enum sev_cmd_id { @@ -65,7 +65,7 @@ index a61be972c..8595dd5ca 100644 #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) diff --git a/target/i386/csv.h b/target/i386/csv.h -index 4c1ef2002..2a3a3119d 100644 +index 4c1ef20..2a3a311 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -54,5 +54,6 @@ struct CsvBatchCmdList { @@ -76,7 +76,7 @@ index 4c1ef2002..2a3a3119d 100644 #endif diff --git a/target/i386/sev.c b/target/i386/sev.c -index 027249e44..cfbc9fb59 100644 +index 027249e..cfbc9fb 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -191,6 +191,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { @@ -189,7 +189,7 @@ index 027249e44..cfbc9fb59 100644 .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21) diff --git a/target/i386/sev.h b/target/i386/sev.h -index 84e3bdf2d..f7886116e 100644 +index 84e3bdf..f788611 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -41,6 +41,9 @@ typedef struct SevKernelLoaderContext { @@ -203,5 +203,5 @@ index 84e3bdf2d..f7886116e 100644 bool sev_enabled(void); bool sev_es_enabled(void); -- -2.31.1 +1.8.3.1 diff --git a/1025-target-i386-csv-add-support-to-queue-the-incoming-pa.patch b/0209-target-i386-csv-add-support-to-queue-the-incoming-pa.patch similarity index 94% rename from 1025-target-i386-csv-add-support-to-queue-the-incoming-pa.patch rename to 0209-target-i386-csv-add-support-to-queue-the-incoming-pa.patch index 97c5325a9ea1d3c61e38df3c892eca143ab56e7c..26d986f3d3e19a27292f25254f281cb439823a6a 100644 --- a/1025-target-i386-csv-add-support-to-queue-the-incoming-pa.patch +++ b/0209-target-i386-csv-add-support-to-queue-the-incoming-pa.patch @@ -1,7 +1,7 @@ -From df598a3d495b5351f6c15a27ba4d3ab1139c852b Mon Sep 17 00:00:00 2001 +From ec780ff02209bc4fed0f517e4b8cc5962182e428 Mon Sep 17 00:00:00 2001 From: fangbaoshun Date: Mon, 2 Aug 2021 13:49:48 +0800 -Subject: [PATCH 21/28] target/i386: csv: add support to queue the incoming +Subject: [PATCH 219/293] target/i386: csv: add support to queue the incoming page into a list The csv_queue_incoming_page() provide the implementation to queue the @@ -13,11 +13,11 @@ Signed-off-by: hanliyang --- include/exec/confidential-guest-support.h | 3 + target/i386/csv.h | 1 + - target/i386/sev.c | 92 +++++++++++++++++++++++ + target/i386/sev.c | 92 +++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index c84f8c1ef..101cc5220 100644 +index c84f8c1..101cc52 100644 --- a/include/exec/confidential-guest-support.h +++ b/include/exec/confidential-guest-support.h @@ -84,6 +84,9 @@ struct ConfidentialGuestMemoryEncryptionOps { @@ -31,7 +31,7 @@ index c84f8c1ef..101cc5220 100644 typedef struct ConfidentialGuestSupportClass { diff --git a/target/i386/csv.h b/target/i386/csv.h -index 2a3a3119d..d1bcc8bc1 100644 +index 2a3a311..d1bcc8b 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -55,5 +55,6 @@ struct CsvBatchCmdList { @@ -42,7 +42,7 @@ index 2a3a3119d..d1bcc8bc1 100644 #endif diff --git a/target/i386/sev.c b/target/i386/sev.c -index cfbc9fb59..97e2e7153 100644 +index cfbc9fb..97e2e71 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -192,6 +192,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { @@ -69,11 +69,10 @@ index cfbc9fb59..97e2e7153 100644 static int csv_send_queue_data(SevGuestState *s, uint8_t *ptr, uint32_t size, uint64_t addr) -@@ -2012,6 +2022,66 @@ err: - return ret; +@@ -2013,6 +2023,66 @@ err: } -+static int + static int +csv_receive_queue_data(SevGuestState *s, QEMUFile *f, uint8_t *ptr) +{ + int ret = 0; @@ -133,9 +132,10 @@ index cfbc9fb59..97e2e7153 100644 + return ret; +} + - static int ++static int csv_command_batch(uint32_t cmd_id, uint64_t head_uaddr, int *fw_err) { + int ret; @@ -2089,6 +2159,28 @@ csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) return csv_send_queue_data(s, ptr, sz, addr); } @@ -166,5 +166,5 @@ index cfbc9fb59..97e2e7153 100644 csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) { -- -2.31.1 +1.8.3.1 diff --git a/1026-target-i386-csv-add-support-to-load-incoming-encrypt.patch b/0210-target-i386-csv-add-support-to-load-incoming-encrypt.patch similarity index 93% rename from 1026-target-i386-csv-add-support-to-load-incoming-encrypt.patch rename to 0210-target-i386-csv-add-support-to-load-incoming-encrypt.patch index fea18de439710745ddf6c8e5582b302e0218f2a6..f18ad465a71ed8816071dfe0a4c07cb404b943f2 100644 --- a/1026-target-i386-csv-add-support-to-load-incoming-encrypt.patch +++ b/0210-target-i386-csv-add-support-to-load-incoming-encrypt.patch @@ -1,7 +1,7 @@ -From 6248758d909135ec632ecd952007161f99a6f376 Mon Sep 17 00:00:00 2001 +From 2e1b9eedc61e2643aa74a3dd20abe6eef41fa492 Mon Sep 17 00:00:00 2001 From: fangbaoshun Date: Mon, 2 Aug 2021 14:11:43 +0800 -Subject: [PATCH 22/28] target/i386: csv: add support to load incoming +Subject: [PATCH 220/293] target/i386: csv: add support to load incoming encrypted pages queued in the CMD list The csv_load_queued_incoming_pages() provide the implementation to read the @@ -17,11 +17,11 @@ Signed-off-by: hanliyang --- include/exec/confidential-guest-support.h | 3 +++ target/i386/csv.h | 1 + - target/i386/sev.c | 32 +++++++++++++++++++++++ + target/i386/sev.c | 32 +++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 101cc5220..cb14b815c 100644 +index 101cc52..cb14b81 100644 --- a/include/exec/confidential-guest-support.h +++ b/include/exec/confidential-guest-support.h @@ -87,6 +87,9 @@ struct ConfidentialGuestMemoryEncryptionOps { @@ -35,7 +35,7 @@ index 101cc5220..cb14b815c 100644 typedef struct ConfidentialGuestSupportClass { diff --git a/target/i386/csv.h b/target/i386/csv.h -index d1bcc8bc1..977f08b98 100644 +index d1bcc8b..977f08b 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -56,5 +56,6 @@ struct CsvBatchCmdList { @@ -46,7 +46,7 @@ index d1bcc8bc1..977f08b98 100644 #endif diff --git a/target/i386/sev.c b/target/i386/sev.c -index 97e2e7153..8e5da510d 100644 +index 97e2e71..8e5da51 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -193,6 +193,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { @@ -103,5 +103,5 @@ index 97e2e7153..8e5da510d 100644 .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21) -- -2.31.1 +1.8.3.1 diff --git a/1027-migration-ram-Accelerate-the-transmission-of-CSV-gue.patch b/0211-migration-ram-Accelerate-the-transmission-of-CSV-gue.patch similarity index 95% rename from 1027-migration-ram-Accelerate-the-transmission-of-CSV-gue.patch rename to 0211-migration-ram-Accelerate-the-transmission-of-CSV-gue.patch index 3c29f2e2999d825c5d89b35b6f9fed8ac21d69b3..be1c55a8e2b6fbffa31cc53bb0a0a4c68dce44e6 100644 --- a/1027-migration-ram-Accelerate-the-transmission-of-CSV-gue.patch +++ b/0211-migration-ram-Accelerate-the-transmission-of-CSV-gue.patch @@ -1,7 +1,7 @@ -From c48d56c99370549e32a9fc79c9d14e1336b6b843 Mon Sep 17 00:00:00 2001 +From f2e133370d44aaa49a74ee1481dc469619adef53 Mon Sep 17 00:00:00 2001 From: fangbaoshun Date: Mon, 2 Aug 2021 14:35:51 +0800 -Subject: [PATCH 23/28] migration/ram: Accelerate the transmission of CSV +Subject: [PATCH 221/293] migration/ram: Accelerate the transmission of CSV guest's encrypted pages When memory encryption is enabled, the guest memory will be encrypted with @@ -11,13 +11,13 @@ queued the pages into list and send them togather by COMMAND_BATCH. Signed-off-by: hanliyang --- configs/devices/i386-softmmu/default.mak | 1 + - hw/i386/Kconfig | 5 + - migration/ram.c | 119 +++++++++++++++++++++++ + hw/i386/Kconfig | 5 ++ + migration/ram.c | 119 +++++++++++++++++++++++++++++++ target/i386/csv.h | 2 + 4 files changed, 127 insertions(+) diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak -index db83ffcab..e948e54e4 100644 +index db83ffc..e948e54 100644 --- a/configs/devices/i386-softmmu/default.mak +++ b/configs/devices/i386-softmmu/default.mak @@ -24,6 +24,7 @@ @@ -29,7 +29,7 @@ index db83ffcab..e948e54e4 100644 # Boards: # diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig -index 08f3ae43f..682e324f1 100644 +index 08f3ae4..682e324 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -12,8 +12,13 @@ config SGX @@ -47,7 +47,7 @@ index 08f3ae43f..682e324f1 100644 bool imply APPLESMC diff --git a/migration/ram.c b/migration/ram.c -index 22f07a064..be8dca326 100644 +index 22f07a0..be8dca3 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -67,6 +67,7 @@ @@ -191,7 +191,7 @@ index 22f07a064..be8dca326 100644 pss_host_page_prepare(pss); diff --git a/target/i386/csv.h b/target/i386/csv.h -index 977f08b98..74a54f9b9 100644 +index 977f08b..74a54f9 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -44,6 +44,8 @@ static bool __attribute__((unused)) is_hygon_cpu(void) @@ -204,5 +204,5 @@ index 977f08b98..74a54f9b9 100644 typedef void (*CsvDestroyCmdNodeFn) (void *data); -- -2.31.1 +1.8.3.1 diff --git a/1028-migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch b/0212-migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch similarity index 87% rename from 1028-migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch rename to 0212-migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch index b8498f357be9e5769e31197c075706de48b6bb24..8869ea3e5d06b1e8af02fda943ad309668638b1c 100644 --- a/1028-migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch +++ b/0212-migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch @@ -1,7 +1,7 @@ -From 62434ee38c7097aec5e5f67b56ae96d6b6ab2162 Mon Sep 17 00:00:00 2001 +From d96daa85a535a5363592de1c3784ae744a2c4115 Mon Sep 17 00:00:00 2001 From: fangbaoshun Date: Mon, 2 Aug 2021 14:49:45 +0800 -Subject: [PATCH 24/28] migration/ram: Accelerate the loading of CSV guest's +Subject: [PATCH 222/293] migration/ram: Accelerate the loading of CSV guest's encrypted pages When memory encryption is enabled, the guest memory will be encrypted with @@ -14,7 +14,7 @@ Signed-off-by: hanliyang 1 file changed, 8 insertions(+) diff --git a/migration/ram.c b/migration/ram.c -index be8dca326..c7245aa4d 100644 +index be8dca3..c7245aa 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1295,6 +1295,14 @@ static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) @@ -33,5 +33,5 @@ index be8dca326..c7245aa4d 100644 error_report("unknown encrypted flag %x", flag); return 1; -- -2.31.1 +1.8.3.1 diff --git a/1029-target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch b/0213-target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch similarity index 96% rename from 1029-target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch rename to 0213-target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch index 9bcd217fe7371eda200be049df363c652765d3eb..000986aed5c2f2f4094ba00d055f9d030156a7d9 100644 --- a/1029-target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch +++ b/0213-target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch @@ -1,8 +1,8 @@ -From 86144110e4cd8f2cba918c22127659e5046b623d Mon Sep 17 00:00:00 2001 +From c9e9fc38be4fdf97fdc6f6adce29699f3bef01da Mon Sep 17 00:00:00 2001 From: hanliyang Date: Tue, 7 Jun 2022 15:19:32 +0800 -Subject: [PATCH 25/28] target/i386: csv: Add support for migrate VMSA for CSV2 - guest +Subject: [PATCH 223/293] target/i386: csv: Add support for migrate VMSA for + CSV2 guest CSV2 can protect guest's cpu state through memory encryption. Each vcpu has its corresponding memory, which is also called VMSA, and @@ -29,16 +29,16 @@ invoke RECEIVE_UPDATE_VMSA to restore VMSA correspond to vcpu. Signed-off-by: hanliyang --- include/exec/confidential-guest-support.h | 6 + - linux-headers/linux/kvm.h | 16 ++ - migration/ram.c | 42 +++++ + linux-headers/linux/kvm.h | 16 +++ + migration/ram.c | 42 +++++++ target/i386/csv.h | 2 + - target/i386/sev.c | 201 ++++++++++++++++++++++ + target/i386/sev.c | 201 ++++++++++++++++++++++++++++++ target/i386/sev.h | 1 + target/i386/trace-events | 2 + 7 files changed, 270 insertions(+) diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index cb14b815c..2cba27642 100644 +index cb14b81..2cba276 100644 --- a/include/exec/confidential-guest-support.h +++ b/include/exec/confidential-guest-support.h @@ -90,6 +90,12 @@ struct ConfidentialGuestMemoryEncryptionOps { @@ -55,7 +55,7 @@ index cb14b815c..2cba27642 100644 typedef struct ConfidentialGuestSupportClass { diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 8595dd5ca..2ed7ae472 100644 +index 8595dd5..2ed7ae4 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -2009,6 +2009,14 @@ struct kvm_sev_send_update_data { @@ -89,7 +89,7 @@ index 8595dd5ca..2ed7ae472 100644 __u64 cmd_data_addr; __u64 addr; diff --git a/migration/ram.c b/migration/ram.c -index c7245aa4d..198b06000 100644 +index c7245aa..198b060 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1279,6 +1279,33 @@ static int ram_save_shared_region_list(RAMState *rs, QEMUFile *f) @@ -156,7 +156,7 @@ index c7245aa4d..198b06000 100644 } diff --git a/target/i386/csv.h b/target/i386/csv.h -index 74a54f9b9..47741a0a4 100644 +index 74a54f9..47741a0 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -59,5 +59,7 @@ int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); @@ -168,7 +168,7 @@ index 74a54f9b9..47741a0a4 100644 #endif diff --git a/target/i386/sev.c b/target/i386/sev.c -index 8e5da510d..52693ae8b 100644 +index 8e5da51..52693ae 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -90,6 +90,10 @@ struct SevGuestState { @@ -408,7 +408,7 @@ index 8e5da510d..52693ae8b 100644 .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21) diff --git a/target/i386/sev.h b/target/i386/sev.h -index f7886116e..209c92fd6 100644 +index f788611..209c92f 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -43,6 +43,7 @@ typedef struct SevKernelLoaderContext { @@ -420,7 +420,7 @@ index f7886116e..209c92fd6 100644 #ifdef CONFIG_SEV bool sev_enabled(void); diff --git a/target/i386/trace-events b/target/i386/trace-events -index 475de65ad..87b765c73 100644 +index 475de65..87b765c 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -17,3 +17,5 @@ kvm_sev_send_finish(void) "" @@ -430,5 +430,5 @@ index 475de65ad..87b765c73 100644 +kvm_sev_send_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *dst, int len) "cpu_id %d cpu_index %d trans %p len %d" +kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int len, void *hdr, int hdr_len) "cpu_id %d cpu_index %d trans %p len %d hdr %p hdr_len %d" -- -2.31.1 +1.8.3.1 diff --git a/1030-target-i386-get-set-migrate-GHCB-state.patch b/0214-target-i386-get-set-migrate-GHCB-state.patch similarity index 91% rename from 1030-target-i386-get-set-migrate-GHCB-state.patch rename to 0214-target-i386-get-set-migrate-GHCB-state.patch index 5ec9dd798ecd6b810aef394420f1846696cfe517..1774fcb5608b096c8d3b4a1a4c01c6462130e41a 100644 --- a/1030-target-i386-get-set-migrate-GHCB-state.patch +++ b/0214-target-i386-get-set-migrate-GHCB-state.patch @@ -1,7 +1,7 @@ -From b1e7543269ba3a0d562d22a07a295abb576aa598 Mon Sep 17 00:00:00 2001 +From 6503910c5467f56bd09a94af3c13b7b7284447f7 Mon Sep 17 00:00:00 2001 From: panpingsheng Date: Sat, 12 Jun 2021 15:15:29 +0800 -Subject: [PATCH 26/28] target/i386: get/set/migrate GHCB state +Subject: [PATCH 224/293] target/i386: get/set/migrate GHCB state GHCB state is necessary to CSV2 guest when migrating to target. @@ -20,7 +20,7 @@ Signed-off-by: hanliyang 7 files changed, 56 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 2ed7ae472..bdcd7a014 100644 +index 2ed7ae4..bdcd7a0 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1199,6 +1199,8 @@ struct kvm_ppc_resize_hpt { @@ -33,10 +33,10 @@ index 2ed7ae472..bdcd7a014 100644 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index ef987f344..09041a5f5 100644 +index 877fc2b..9fc24f7 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h -@@ -519,6 +519,8 @@ typedef enum X86Seg { +@@ -521,6 +521,8 @@ typedef enum X86Seg { #define MSR_VM_HSAVE_PA 0xc0010117 @@ -45,7 +45,7 @@ index ef987f344..09041a5f5 100644 #define MSR_IA32_XFD 0x000001c4 #define MSR_IA32_XFD_ERR 0x000001c5 -@@ -1884,6 +1886,9 @@ typedef struct CPUArchState { +@@ -1888,6 +1890,9 @@ typedef struct CPUArchState { /* Number of dies within this CPU package. */ unsigned nr_dies; @@ -56,7 +56,7 @@ index ef987f344..09041a5f5 100644 struct kvm_msrs; diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 5730d0e0c..9e6524273 100644 +index 5730d0e..9e65242 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -3625,6 +3625,10 @@ static int kvm_put_msrs(X86CPU *cpu, int level) @@ -92,7 +92,7 @@ index 5730d0e0c..9e6524273 100644 } diff --git a/target/i386/kvm/sev-stub.c b/target/i386/kvm/sev-stub.c -index 99899688e..a0aac1117 100644 +index 9989968..a0aac11 100644 --- a/target/i386/kvm/sev-stub.c +++ b/target/i386/kvm/sev-stub.c @@ -14,6 +14,8 @@ @@ -105,7 +105,7 @@ index 99899688e..a0aac1117 100644 { /* If we get here, cgs must be some non-SEV thing */ diff --git a/target/i386/machine.c b/target/i386/machine.c -index a1041ef82..9a1cb8f3b 100644 +index a1041ef..9a1cb8f 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -1605,6 +1605,27 @@ static const VMStateDescription vmstate_triple_fault = { @@ -147,7 +147,7 @@ index a1041ef82..9a1cb8f3b 100644 } }; diff --git a/target/i386/sev.c b/target/i386/sev.c -index 52693ae8b..71d317e86 100644 +index 52693ae..71d317e 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -152,6 +152,8 @@ QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0); @@ -175,7 +175,7 @@ index 52693ae8b..71d317e86 100644 return 0; diff --git a/target/i386/sev.h b/target/i386/sev.h -index 209c92fd6..0bfe3879e 100644 +index 209c92f..0bfe387 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -78,4 +78,6 @@ void sev_del_migrate_blocker(void); @@ -186,5 +186,5 @@ index 209c92fd6..0bfe3879e 100644 + #endif -- -2.31.1 +1.8.3.1 diff --git a/1031-target-i386-kvm-Fix-the-resettable-info-when-emulate.patch b/0215-target-i386-kvm-Fix-the-resettable-info-when-emulate.patch similarity index 92% rename from 1031-target-i386-kvm-Fix-the-resettable-info-when-emulate.patch rename to 0215-target-i386-kvm-Fix-the-resettable-info-when-emulate.patch index 7bb0155cec58ac457186282e0456c4d12ff0e6bd..6f96b88e20a0d67c8bd58ff47c0106cba9b6781d 100644 --- a/1031-target-i386-kvm-Fix-the-resettable-info-when-emulate.patch +++ b/0215-target-i386-kvm-Fix-the-resettable-info-when-emulate.patch @@ -1,7 +1,7 @@ -From 35872adf8405bcbaf37bbd5a79b7cb1d1f28ace0 Mon Sep 17 00:00:00 2001 +From 641fe421b552336c5dfb7f3e6840903e3e5b95ba Mon Sep 17 00:00:00 2001 From: hanliyang Date: Sun, 19 Jun 2022 16:49:45 +0800 -Subject: [PATCH 27/28] target/i386/kvm: Fix the resettable info when emulate +Subject: [PATCH 225/293] target/i386/kvm: Fix the resettable info when emulate Hygon CSV2 guest SEV-ES guest will be terminated by QEMU when receive reboot request. @@ -26,7 +26,7 @@ Signed-off-by: hanliyang diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c new file mode 100644 -index 000000000..5874e4cc1 +index 0000000..5874e4c --- /dev/null +++ b/target/i386/csv-sysemu-stub.c @@ -0,0 +1,16 @@ @@ -48,7 +48,7 @@ index 000000000..5874e4cc1 +#include "csv.h" diff --git a/target/i386/csv.c b/target/i386/csv.c new file mode 100644 -index 000000000..88fb05ac3 +index 0000000..88fb05a --- /dev/null +++ b/target/i386/csv.c @@ -0,0 +1,20 @@ @@ -73,7 +73,7 @@ index 000000000..88fb05ac3 + +bool csv_kvm_cpu_reset_inhibit; diff --git a/target/i386/csv.h b/target/i386/csv.h -index 47741a0a4..ac4bb5bee 100644 +index 47741a0..ac4bb5b 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -46,6 +46,8 @@ static bool __attribute__((unused)) is_hygon_cpu(void) @@ -87,7 +87,7 @@ index 47741a0a4..ac4bb5bee 100644 diff --git a/target/i386/kvm/csv-stub.c b/target/i386/kvm/csv-stub.c new file mode 100644 -index 000000000..4d1376f26 +index 0000000..4d1376f --- /dev/null +++ b/target/i386/kvm/csv-stub.c @@ -0,0 +1,17 @@ @@ -109,7 +109,7 @@ index 000000000..4d1376f26 + +bool csv_kvm_cpu_reset_inhibit; diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 9e6524273..2866a6d0e 100644 +index 9e65242..2866a6d 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -32,6 +32,7 @@ @@ -131,7 +131,7 @@ index 9e6524273..2866a6d0e 100644 } diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build -index 84d9143e6..3c3f8cf93 100644 +index 84d9143..3c3f8cf 100644 --- a/target/i386/kvm/meson.build +++ b/target/i386/kvm/meson.build @@ -8,6 +8,7 @@ i386_kvm_ss.add(files( @@ -143,7 +143,7 @@ index 84d9143e6..3c3f8cf93 100644 i386_system_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c')) diff --git a/target/i386/meson.build b/target/i386/meson.build -index 7c74bfa85..594a0a6ab 100644 +index 7c74bfa..594a0a6 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build @@ -21,6 +21,7 @@ i386_system_ss.add(files( @@ -155,7 +155,7 @@ index 7c74bfa85..594a0a6ab 100644 i386_user_ss = ss.source_set() diff --git a/target/i386/sev.c b/target/i386/sev.c -index 71d317e86..3406861f6 100644 +index 71d317e..3406861 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -1190,6 +1190,15 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) @@ -175,5 +175,5 @@ index 71d317e86..3406861f6 100644 ram_block_notifier_add(&sev_ram_notifier); -- -2.31.1 +1.8.3.1 diff --git a/1032-kvm-Add-support-for-CSV2-reboot.patch b/0216-kvm-Add-support-for-CSV2-reboot.patch similarity index 93% rename from 1032-kvm-Add-support-for-CSV2-reboot.patch rename to 0216-kvm-Add-support-for-CSV2-reboot.patch index c08a105eb89e56e8faa13e439c5e73d5461edf32..ea7bb857a0cd5b35837514a7bd2e1c6732699bf9 100644 --- a/1032-kvm-Add-support-for-CSV2-reboot.patch +++ b/0216-kvm-Add-support-for-CSV2-reboot.patch @@ -1,7 +1,7 @@ -From 04158d0c919c406aafa5f5a366c48484dfe92c14 Mon Sep 17 00:00:00 2001 +From 63ef0cc04f7e80891de6aa80910980ebf3ff758f Mon Sep 17 00:00:00 2001 From: hanliyang Date: Thu, 15 Apr 2021 08:32:24 -0400 -Subject: [PATCH 28/28] kvm: Add support for CSV2 reboot +Subject: [PATCH 226/293] kvm: Add support for CSV2 reboot Linux will set vcpu.arch.guest_state_protected to true after execute LAUNCH_UPDATE_VMSA successfully, and then KVM will prevent any changes @@ -30,7 +30,7 @@ Signed-off-by: hanliyang 8 files changed, 43 insertions(+) diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c -index 6195150a0..54f19028b 100644 +index 6195150..54f1902 100644 --- a/accel/kvm/kvm-accel-ops.c +++ b/accel/kvm/kvm-accel-ops.c @@ -112,6 +112,9 @@ static void kvm_accel_ops_class_init(ObjectClass *oc, void *data) @@ -44,7 +44,7 @@ index 6195150a0..54f19028b 100644 static const TypeInfo kvm_accel_ops_type = { diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index e39a810a4..e5ed69c33 100644 +index e39a810..e5ed69c 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -2761,6 +2761,16 @@ void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu) @@ -65,7 +65,7 @@ index e39a810a4..e5ed69c33 100644 static __thread void *pending_sigbus_addr; static __thread int pending_sigbus_code; diff --git a/accel/kvm/kvm-cpus.h b/accel/kvm/kvm-cpus.h -index ca40add32..27b9d0d9d 100644 +index ca40add..27b9d0d 100644 --- a/accel/kvm/kvm-cpus.h +++ b/accel/kvm/kvm-cpus.h @@ -23,4 +23,7 @@ int kvm_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len); @@ -77,7 +77,7 @@ index ca40add32..27b9d0d9d 100644 + #endif /* KVM_CPUS_H */ diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h -index ef91fc28b..7a32e7f82 100644 +index ef91fc2..7a32e7f 100644 --- a/include/sysemu/accel-ops.h +++ b/include/sysemu/accel-ops.h @@ -53,6 +53,9 @@ struct AccelOpsClass { @@ -91,7 +91,7 @@ index ef91fc28b..7a32e7f82 100644 #endif /* ACCEL_OPS_H */ diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h -index b4a566cfe..f24d27daf 100644 +index b4a566c..f24d27d 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -44,6 +44,8 @@ extern int icount_align_option; @@ -104,7 +104,7 @@ index b4a566cfe..f24d27daf 100644 void cpu_synchronize_all_states(void); void cpu_synchronize_all_post_reset(void); diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index bdcd7a014..372d0bd14 100644 +index bdcd7a0..372d0bd 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1583,6 +1583,10 @@ struct kvm_s390_ucas_mapping { @@ -119,7 +119,7 @@ index bdcd7a014..372d0bd14 100644 * ioctls for vcpu fds */ diff --git a/system/cpus.c b/system/cpus.c -index a444a747f..cbeec13f3 100644 +index a444a74..cbeec13 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -193,6 +193,20 @@ void cpu_synchronize_pre_loadvm(CPUState *cpu) @@ -144,7 +144,7 @@ index a444a747f..cbeec13f3 100644 { if (cpus_accel->cpus_are_resettable) { diff --git a/system/runstate.c b/system/runstate.c -index ea9d6c2a3..365f2f44b 100644 +index ea9d6c2..365f2f4 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -486,6 +486,8 @@ void qemu_system_reset(ShutdownCause reason) @@ -166,5 +166,5 @@ index ea9d6c2a3..365f2f44b 100644 /* -- -2.31.1 +1.8.3.1 diff --git a/1033-target-i386-csv-Add-CSV3-context.patch b/0217-target-i386-csv-Add-CSV3-context.patch similarity index 90% rename from 1033-target-i386-csv-Add-CSV3-context.patch rename to 0217-target-i386-csv-Add-CSV3-context.patch index 880f4c2ae67e91fd79f489d0395fcb22cb098d94..0d664295babfefa6f5974ebe90d9b515cdfcb5f7 100644 --- a/1033-target-i386-csv-Add-CSV3-context.patch +++ b/0217-target-i386-csv-Add-CSV3-context.patch @@ -1,7 +1,7 @@ -From d9da5a2694de340197ff8e51080f112af8bfff5c Mon Sep 17 00:00:00 2001 +From 87af3b6cab2252a01cb2f2eee7a85f74d3e90e0b Mon Sep 17 00:00:00 2001 From: jiangxin Date: Tue, 24 Aug 2021 14:57:28 +0800 -Subject: [PATCH 01/14] target/i386: csv: Add CSV3 context +Subject: [PATCH 227/293] target/i386: csv: Add CSV3 context CSV/CSV2/CSV3 are the secure virtualization features on Hygon CPUs. The CSV and CSV2 are compatible with the AMD SEV and SEV-ES, @@ -19,7 +19,7 @@ Signed-off-by: hanliyang 2 files changed, 29 insertions(+) diff --git a/target/i386/csv.c b/target/i386/csv.c -index 88fb05ac3..9a1de04db 100644 +index 88fb05a..9a1de04 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -18,3 +18,14 @@ @@ -38,7 +38,7 @@ index 88fb05ac3..9a1de04db 100644 + return sev_es_enabled() && (csv3_guest.policy & GUEST_POLICY_CSV3_BIT); +} diff --git a/target/i386/csv.h b/target/i386/csv.h -index ac4bb5bee..7852fb8dc 100644 +index ac4bb5b..7852fb8 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -14,6 +14,8 @@ @@ -82,5 +82,5 @@ index ac4bb5bee..7852fb8dc 100644 + #endif -- -2.31.1 +1.8.3.1 diff --git a/1034-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch b/0218-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch similarity index 90% rename from 1034-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch rename to 0218-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch index 7e8bf484b787141d2bef77700214dca9bf158ec5..2212c96a0d8cc36f6e50e65263b98ed6f93cff17 100644 --- a/1034-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch +++ b/0218-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch @@ -1,7 +1,7 @@ -From ab6316e662eac3bd66085d50d33153d8205b2334 Mon Sep 17 00:00:00 2001 +From 38d00f2f50a36352047f8ab60a62b211ffe6ca2c Mon Sep 17 00:00:00 2001 From: jiangxin Date: Wed, 25 Aug 2021 11:07:41 +0800 -Subject: [PATCH 02/14] target/i386: csv: Add command to initialize CSV3 +Subject: [PATCH 228/293] target/i386: csv: Add command to initialize CSV3 context When CSV3 is enabled, KVM_CSV3_INIT command is used to initialize @@ -14,16 +14,16 @@ any other command. Signed-off-by: Xin Jiang Signed-off-by: hanliyang --- - linux-headers/linux/kvm.h | 11 +++++++++ - target/i386/csv-sysemu-stub.c | 5 ++++ - target/i386/csv.c | 45 +++++++++++++++++++++++++++++++++++ + linux-headers/linux/kvm.h | 11 +++++++++++ + target/i386/csv-sysemu-stub.c | 5 +++++ + target/i386/csv.c | 45 +++++++++++++++++++++++++++++++++++++++++++ target/i386/csv.h | 4 ++++ - target/i386/sev.c | 17 +++++++++++++ - target/i386/sev.h | 7 ++++++ + target/i386/sev.c | 17 ++++++++++++++++ + target/i386/sev.h | 7 +++++++ 6 files changed, 89 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 372d0bd14..d976908bc 100644 +index 372d0bd..d976908 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -2060,6 +2060,17 @@ struct kvm_csv_command_batch { @@ -45,7 +45,7 @@ index 372d0bd14..d976908bc 100644 #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index 5874e4cc1..72f0f5c77 100644 +index 5874e4c..72f0f5c 100644 --- a/target/i386/csv-sysemu-stub.c +++ b/target/i386/csv-sysemu-stub.c @@ -14,3 +14,8 @@ @@ -58,7 +58,7 @@ index 5874e4cc1..72f0f5c77 100644 + return 0; +} diff --git a/target/i386/csv.c b/target/i386/csv.c -index 9a1de04db..f02aadb54 100644 +index 9a1de04..f02aadb 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -12,6 +12,13 @@ @@ -121,7 +121,7 @@ index 9a1de04db..f02aadb54 100644 csv3_enabled(void) { diff --git a/target/i386/csv.h b/target/i386/csv.h -index 7852fb8dc..cf125fe0f 100644 +index 7852fb8..cf125fe 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -15,6 +15,7 @@ @@ -147,7 +147,7 @@ index 7852fb8dc..cf125fe0f 100644 #endif diff --git a/target/i386/sev.c b/target/i386/sev.c -index 3406861f6..50f3429a4 100644 +index 3406861..50f3429 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -1180,6 +1180,18 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) @@ -182,7 +182,7 @@ index 3406861f6..50f3429a4 100644 sev_register_types(void) { diff --git a/target/i386/sev.h b/target/i386/sev.h -index 0bfe3879e..e91431e0f 100644 +index 0bfe387..e91431e 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -80,4 +80,11 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); @@ -198,5 +198,5 @@ index 0bfe3879e..e91431e0f 100644 + #endif -- -2.31.1 +1.8.3.1 diff --git a/1035-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch b/0219-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch similarity index 90% rename from 1035-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch rename to 0219-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch index ca4a3aeb051b4b6fe237c11937bdf201f02a1c45..a8876e5210d904198ee55ce71a9338a976e41333 100644 --- a/1035-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch +++ b/0219-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch @@ -1,7 +1,7 @@ -From 39ab65c4235b733a1a4e0147be3f81881fb1c551 Mon Sep 17 00:00:00 2001 +From e7d21782f961f95f3fb2fa93b6135f51976ea040 Mon Sep 17 00:00:00 2001 From: jiangxin Date: Wed, 25 Aug 2021 09:59:16 +0800 -Subject: [PATCH 03/14] target/i386: csv: Add command to load data to CSV3 +Subject: [PATCH 229/293] target/i386: csv: Add command to load data to CSV3 guest memory The KVM_CSV3_LAUNCH_ENCRYPT_DATA command is used to load data to an @@ -10,15 +10,15 @@ encrypted guest memory in an isolated memory region that guest owns. Signed-off-by: Xin Jiang Signed-off-by: hanliyang --- - linux-headers/linux/kvm.h | 7 ++++ - target/i386/csv-sysemu-stub.c | 5 +++ - target/i386/csv.c | 69 +++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 2 + + linux-headers/linux/kvm.h | 7 +++++ + target/i386/csv-sysemu-stub.c | 5 ++++ + target/i386/csv.c | 69 +++++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 2 ++ target/i386/trace-events | 3 ++ 5 files changed, 86 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index d976908bc..fa7b41581 100644 +index d976908..fa7b415 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -2065,6 +2065,13 @@ enum csv3_cmd_id { @@ -36,7 +36,7 @@ index d976908bc..fa7b41581 100644 struct kvm_csv3_init_data { diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index 72f0f5c77..b0ccbd2f1 100644 +index 72f0f5c..b0ccbd2 100644 --- a/target/i386/csv-sysemu-stub.c +++ b/target/i386/csv-sysemu-stub.c @@ -19,3 +19,8 @@ int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) @@ -49,7 +49,7 @@ index 72f0f5c77..b0ccbd2f1 100644 + g_assert_not_reached(); +} diff --git a/target/i386/csv.c b/target/i386/csv.c -index f02aadb54..0e3f4478a 100644 +index f02aadb..0e3f447 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -13,6 +13,7 @@ @@ -140,7 +140,7 @@ index f02aadb54..0e3f4478a 100644 + return ret; +} diff --git a/target/i386/csv.h b/target/i386/csv.h -index cf125fe0f..928774f59 100644 +index cf125fe..928774f 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -86,4 +86,6 @@ typedef struct Csv3GuestState Csv3GuestState; @@ -151,7 +151,7 @@ index cf125fe0f..928774f59 100644 + #endif diff --git a/target/i386/trace-events b/target/i386/trace-events -index 87b765c73..e07061bf3 100644 +index 87b765c..e07061b 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -19,3 +19,6 @@ kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_le @@ -162,5 +162,5 @@ index 87b765c73..e07061bf3 100644 +# csv.c +kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 -- -2.31.1 +1.8.3.1 diff --git a/1036-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch b/0220-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch similarity index 90% rename from 1036-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch rename to 0220-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch index febed2638d656f38345b4065cd187e20464167c3..87bde58cd69f0cdfa954d4016e5289d8b14e0a61 100644 --- a/1036-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch +++ b/0220-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch @@ -1,7 +1,7 @@ -From dad06ad8bf5f8ba7842f92f0a92346697740557a Mon Sep 17 00:00:00 2001 +From 70f106ff7e9aaf80a4e114d3027c5b9e41a3fdee Mon Sep 17 00:00:00 2001 From: jiangxin Date: Wed, 25 Aug 2021 12:25:05 +0800 -Subject: [PATCH 04/14] target/i386: csv: Add command to load vmcb to CSV3 +Subject: [PATCH 230/293] target/i386: csv: Add command to load vmcb to CSV3 guest memory The KVM_CSV3_LAUNCH_ENCRYPT_VMCB command is used to load and encrypt @@ -19,7 +19,7 @@ Signed-off-by: hanliyang 5 files changed, 34 insertions(+), 2 deletions(-) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index fa7b41581..061b2e7f0 100644 +index fa7b415..061b2e7 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -2066,6 +2066,7 @@ enum csv3_cmd_id { @@ -31,7 +31,7 @@ index fa7b41581..061b2e7f0 100644 struct kvm_csv3_launch_encrypt_data { diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index b0ccbd2f1..23d885f0f 100644 +index b0ccbd2..23d885f 100644 --- a/target/i386/csv-sysemu-stub.c +++ b/target/i386/csv-sysemu-stub.c @@ -24,3 +24,8 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) @@ -44,7 +44,7 @@ index b0ccbd2f1..23d885f0f 100644 + g_assert_not_reached(); +} diff --git a/target/i386/csv.c b/target/i386/csv.c -index 0e3f4478a..f423b898f 100644 +index 0e3f447..f423b89 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -143,3 +143,24 @@ csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) @@ -73,7 +73,7 @@ index 0e3f4478a..f423b898f 100644 + return ret; +} diff --git a/target/i386/csv.h b/target/i386/csv.h -index 928774f59..6444d54ef 100644 +index 928774f..6444d54 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -85,6 +85,7 @@ typedef struct Csv3GuestState Csv3GuestState; @@ -85,7 +85,7 @@ index 928774f59..6444d54ef 100644 int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); diff --git a/target/i386/sev.c b/target/i386/sev.c -index 50f3429a4..b77572f0b 100644 +index 50f3429..b77572f 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -857,8 +857,12 @@ sev_launch_get_measure(Notifier *notifier, void *unused) @@ -104,5 +104,5 @@ index 50f3429a4..b77572f0b 100644 exit(1); } -- -2.31.1 +1.8.3.1 diff --git a/1037-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch b/0221-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch similarity index 80% rename from 1037-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch rename to 0221-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch index 56c39136d3c4176f76d679c94c6bb8dc322c90f5..978e286438c364926068364e898913caf6a74603 100644 --- a/1037-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch +++ b/0221-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch @@ -1,8 +1,8 @@ -From 94786f0f3fb14205852f0c7ad8c3b4b8fb0ff4fa Mon Sep 17 00:00:00 2001 +From 59fb06b7cca8a87c9b3ab69c99649990843d1611 Mon Sep 17 00:00:00 2001 From: jiangxin Date: Tue, 24 Aug 2021 17:31:28 +0800 -Subject: [PATCH 05/14] target/i386: cpu: Populate CPUID 0x8000_001F when CSV3 - is active +Subject: [PATCH 231/293] target/i386: cpu: Populate CPUID 0x8000_001F when + CSV3 is active On Hygon platform, bit 30 of EAX indicates whether this feature is supported in hardware. @@ -17,7 +17,7 @@ Signed-off-by: hanliyang 1 file changed, 2 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index a66e5a357..c01943ee6 100644 +index ffdaf16..a373d8e 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -29,6 +29,7 @@ @@ -28,7 +28,7 @@ index a66e5a357..c01943ee6 100644 #include "qapi/error.h" #include "qemu/error-report.h" #include "qapi/qapi-visit-machine.h" -@@ -6660,6 +6661,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, +@@ -6808,6 +6809,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, if (sev_enabled()) { *eax = 0x2; *eax |= sev_es_enabled() ? 0x8 : 0; @@ -37,5 +37,5 @@ index a66e5a357..c01943ee6 100644 *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */ } -- -2.31.1 +1.8.3.1 diff --git a/1038-target-i386-csv-Do-not-register-unregister-guest-sec.patch b/0222-target-i386-csv-Do-not-register-unregister-guest-sec.patch similarity index 85% rename from 1038-target-i386-csv-Do-not-register-unregister-guest-sec.patch rename to 0222-target-i386-csv-Do-not-register-unregister-guest-sec.patch index 3a1939c91b1acd7d049d1d9840538033612145ea..73e6ec223356d029ac6a1dbe999713b578f859f7 100644 --- a/1038-target-i386-csv-Do-not-register-unregister-guest-sec.patch +++ b/0222-target-i386-csv-Do-not-register-unregister-guest-sec.patch @@ -1,7 +1,7 @@ -From 1ac5b6d0bef3090fea6fbcc0435cb4215bdf0129 Mon Sep 17 00:00:00 2001 +From e0b432bb2db670059702311dc48749f83ab5a9a9 Mon Sep 17 00:00:00 2001 From: jiangxin Date: Wed, 25 Aug 2021 12:36:00 +0800 -Subject: [PATCH 06/14] target/i386: csv: Do not register/unregister guest +Subject: [PATCH 232/293] target/i386: csv: Do not register/unregister guest secure memory for CSV3 guest CSV3's guest memory is allocated by firmware in secure processor @@ -15,7 +15,7 @@ Signed-off-by: hanliyang 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target/i386/sev.c b/target/i386/sev.c -index b77572f0b..eb1026b57 100644 +index b77572f..eb1026b 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -1217,7 +1217,10 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) @@ -31,5 +31,5 @@ index b77572f0b..eb1026b57 100644 qemu_add_vm_change_state_handler(sev_vm_state_change, sev); migration_add_notifier(&sev_migration_state, sev_migration_state_notifier); -- -2.31.1 +1.8.3.1 diff --git a/1039-target-i386-csv-Load-initial-image-to-private-memory.patch b/0223-target-i386-csv-Load-initial-image-to-private-memory.patch similarity index 87% rename from 1039-target-i386-csv-Load-initial-image-to-private-memory.patch rename to 0223-target-i386-csv-Load-initial-image-to-private-memory.patch index 8a22f5dda7204c6cc28b36d4eb6cb529d39eb371..de7466d303709f84a5b91a8317329b6c250d3ec4 100644 --- a/1039-target-i386-csv-Load-initial-image-to-private-memory.patch +++ b/0223-target-i386-csv-Load-initial-image-to-private-memory.patch @@ -1,8 +1,8 @@ -From 1234dd2391d79ba6a2db3fe82a22822ef7ad9e02 Mon Sep 17 00:00:00 2001 +From 54026b362117c16811e0012b972bed0c25d48254 Mon Sep 17 00:00:00 2001 From: jiangxin Date: Wed, 25 Aug 2021 14:29:40 +0800 -Subject: [PATCH 07/14] target/i386: csv: Load initial image to private memory - for CSV3 guest +Subject: [PATCH 233/293] target/i386: csv: Load initial image to private + memory for CSV3 guest The initial image of CSV3 guest should be loaded into private memory before boot the guest. @@ -16,7 +16,7 @@ Signed-off-by: hanliyang 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c -index c8d9e71b8..2bbcbb8d3 100644 +index c8d9e71..2bbcbb8 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -37,6 +37,7 @@ @@ -48,5 +48,5 @@ index c8d9e71b8..2bbcbb8d3 100644 } } -- -2.31.1 +1.8.3.1 diff --git a/1040-vga-Force-full-update-for-CSV3-guest.patch b/0224-vga-Force-full-update-for-CSV3-guest.patch similarity index 91% rename from 1040-vga-Force-full-update-for-CSV3-guest.patch rename to 0224-vga-Force-full-update-for-CSV3-guest.patch index 49c2b26480652c46dcdbc41ed463a9ffebcbb729..e671c11443c2435abb3a010e3a13f323a1da2847 100644 --- a/1040-vga-Force-full-update-for-CSV3-guest.patch +++ b/0224-vga-Force-full-update-for-CSV3-guest.patch @@ -1,7 +1,7 @@ -From ef998e2666f941ca94f8b5383d574bb886dcf81a Mon Sep 17 00:00:00 2001 +From e2717a7e847de3884927aa50de562b1e611c521a Mon Sep 17 00:00:00 2001 From: Xin Jiang Date: Thu, 13 Jul 2023 09:35:10 +0800 -Subject: [PATCH 08/14] vga: Force full update for CSV3 guest +Subject: [PATCH 234/293] vga: Force full update for CSV3 guest As CSV3's NPT(nested page table) is managed by firmware, VMM is hard to track the dirty pages of vga buffer. Although VMM could perform @@ -21,7 +21,7 @@ Signed-off-by: hanliyang 5 files changed, 20 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index e5ed69c33..25d23bba2 100644 +index e5ed69c..25d23bb 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -98,6 +98,7 @@ bool kvm_allowed; @@ -33,7 +33,7 @@ index e5ed69c33..25d23bba2 100644 static int kvm_sstep_flags; static bool kvm_immediate_exit; diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c -index 1b37d9a30..45b23f61c 100644 +index 1b37d9a..45b23f6 100644 --- a/accel/stubs/kvm-stub.c +++ b/accel/stubs/kvm-stub.c @@ -24,6 +24,7 @@ bool kvm_gsi_direct_mapping; @@ -45,7 +45,7 @@ index 1b37d9a30..45b23f61c 100644 void kvm_flush_coalesced_mmio_buffer(void) { diff --git a/hw/display/vga.c b/hw/display/vga.c -index 37557c344..d70226a89 100644 +index 37557c3..d70226a 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -39,6 +39,8 @@ @@ -70,7 +70,7 @@ index 37557c344..d70226a89 100644 case GMODE_TEXT: vga_draw_text(s, full_update); diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h -index d61487816..1e15cfe9d 100644 +index d614878..1e15cfe 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -42,6 +42,7 @@ extern bool kvm_gsi_routing_allowed; @@ -103,7 +103,7 @@ index d61487816..1e15cfe9d 100644 #endif /* CONFIG_KVM_IS_POSSIBLE */ diff --git a/target/i386/csv.c b/target/i386/csv.c -index f423b898f..70900be86 100644 +index f423b89..70900be 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -14,6 +14,7 @@ @@ -124,5 +124,5 @@ index f423b898f..70900be86 100644 csv3_guest.state = state; csv3_guest.sev_ioctl = ops->sev_ioctl; -- -2.31.1 +1.8.3.1 diff --git a/1041-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch b/0225-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch similarity index 95% rename from 1041-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch rename to 0225-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch index ef0d64cc1e007491b82af65e2b74ad28f91d7f39..303aba0b626bb2fbcf1da164f9f09acd76bc912a 100644 --- a/1041-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch +++ b/0225-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch @@ -1,7 +1,7 @@ -From 0d2dbd4d687ce23342fc072c1d5a64c28f3580c7 Mon Sep 17 00:00:00 2001 +From 201ac3f953d0d30fba075fa74deca9030b242016 Mon Sep 17 00:00:00 2001 From: liuyafei Date: Mon, 22 May 2023 20:37:40 +0800 -Subject: [PATCH 09/14] vfio: Only map shared region for CSV3 virtual machine +Subject: [PATCH 235/293] vfio: Only map shared region for CSV3 virtual machine qemu vfio listener map/unmap all of the virtual machine's memory. It does not work for CSV3 virtual machine, as only shared memory @@ -10,17 +10,17 @@ should be accessed by device. Signed-off-by: liuyafei Signed-off-by: hanliyang --- - hw/vfio/container.c | 46 +++++++++++- - include/exec/memory.h | 11 +++ - system/memory.c | 18 +++++ - target/i386/csv-sysemu-stub.c | 10 +++ - target/i386/csv.c | 134 ++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 12 +++ + hw/vfio/container.c | 46 ++++++++++++++- + include/exec/memory.h | 11 ++++ + system/memory.c | 18 ++++++ + target/i386/csv-sysemu-stub.c | 10 ++++ + target/i386/csv.c | 134 ++++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 12 ++++ target/i386/kvm/kvm.c | 2 + 7 files changed, 230 insertions(+), 3 deletions(-) diff --git a/hw/vfio/container.c b/hw/vfio/container.c -index 242010036..ce075f37d 100644 +index adc3005..0d6e6b4 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -30,6 +30,7 @@ @@ -105,7 +105,7 @@ index 242010036..ce075f37d 100644 container->iommu_type == VFIO_SPAPR_TCE_IOMMU) { vfio_spapr_container_deinit(container); diff --git a/include/exec/memory.h b/include/exec/memory.h -index 831f7c996..3e65d8d9f 100644 +index 831f7c9..3e65d8d 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -775,6 +775,17 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, @@ -127,7 +127,7 @@ index 831f7c996..3e65d8d9f 100644 typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd; diff --git a/system/memory.c b/system/memory.c -index 798b6c0a1..2ffb878eb 100644 +index 798b6c0..2ffb878 100644 --- a/system/memory.c +++ b/system/memory.c @@ -48,6 +48,9 @@ static QTAILQ_HEAD(, MemoryListener) memory_listeners @@ -163,7 +163,7 @@ index 798b6c0a1..2ffb878eb 100644 { uint8_t mask = 1 << client; diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index 23d885f0f..db22c299a 100644 +index 23d885f..db22c29 100644 --- a/target/i386/csv-sysemu-stub.c +++ b/target/i386/csv-sysemu-stub.c @@ -29,3 +29,13 @@ int csv3_launch_encrypt_vmcb(void) @@ -181,7 +181,7 @@ index 23d885f0f..db22c299a 100644 + +} diff --git a/target/i386/csv.c b/target/i386/csv.c -index 70900be86..5823c8994 100644 +index 70900be..5823c89 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -15,6 +15,7 @@ @@ -337,7 +337,7 @@ index 70900be86..5823c8994 100644 + return; +} diff --git a/target/i386/csv.h b/target/i386/csv.h -index 6444d54ef..0c402cefd 100644 +index 6444d54..0c402ce 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -15,6 +15,8 @@ @@ -378,7 +378,7 @@ index 6444d54ef..0c402cefd 100644 + #endif diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 2866a6d0e..925f4f804 100644 +index 2866a6d..925f4f8 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -5026,8 +5026,10 @@ static int kvm_handle_exit_hypercall(X86CPU *cpu, struct kvm_run *run) @@ -393,5 +393,5 @@ index 2866a6d0e..925f4f804 100644 } return 0; -- -2.31.1 +1.8.3.1 diff --git a/1042-linux-headers-update-kernel-headers-to-include-CSV3-.patch b/0226-linux-headers-update-kernel-headers-to-include-CSV3-.patch similarity index 91% rename from 1042-linux-headers-update-kernel-headers-to-include-CSV3-.patch rename to 0226-linux-headers-update-kernel-headers-to-include-CSV3-.patch index ee137076f3888a9332d71ba8536b322bcf05a4a0..5353a8637c068baac44a8034fe2d9e3d52df68d1 100644 --- a/1042-linux-headers-update-kernel-headers-to-include-CSV3-.patch +++ b/0226-linux-headers-update-kernel-headers-to-include-CSV3-.patch @@ -1,7 +1,7 @@ -From 9a1d0fdf779053eba4ba380adeef54d126b87b7b Mon Sep 17 00:00:00 2001 +From dc0446c0bfdd396b36e32a087d662e6923a54d8e Mon Sep 17 00:00:00 2001 From: jiangxin Date: Fri, 17 Jun 2022 09:25:19 +0800 -Subject: [PATCH 10/14] linux-headers: update kernel headers to include CSV3 +Subject: [PATCH 236/293] linux-headers: update kernel headers to include CSV3 migration cmds Four new migration commands are added to support CSV3 migration. @@ -19,7 +19,7 @@ Signed-off-by: hanliyang 1 file changed, 38 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 061b2e7f0..6edf0b33a 100644 +index 061b2e7..6edf0b3 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -2067,6 +2067,12 @@ enum csv3_cmd_id { @@ -75,5 +75,5 @@ index 061b2e7f0..6edf0b33a 100644 #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) -- -2.31.1 +1.8.3.1 diff --git a/1043-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch b/0227-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch similarity index 95% rename from 1043-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch rename to 0227-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch index 079568af057072be1c64ac30714e732fc18394df..6fc9638e5ed11195a1ba827f60c72ec685c10241 100644 --- a/1043-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch +++ b/0227-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch @@ -1,7 +1,7 @@ -From 161f1fdbd8cc76f8859a0f1d92dd3a179cd426e5 Mon Sep 17 00:00:00 2001 +From 70bfd06354b84594921edafc787cc8b56e38d32d Mon Sep 17 00:00:00 2001 From: jiangxin Date: Fri, 17 Jun 2022 09:37:56 +0800 -Subject: [PATCH 11/14] target/i386: csv: Add support to migrate the outgoing +Subject: [PATCH 237/293] target/i386: csv: Add support to migrate the outgoing page for CSV3 guest The csv3_send_encrypt_data() provides the method to encrypt the @@ -14,23 +14,22 @@ command is performed to the firmware. Signed-off-by: Jiang Xin Signed-off-by: hanliyang --- - migration/ram.c | 87 ++++++++++++++++++ - target/i386/csv.c | 184 +++++++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 22 +++++ - target/i386/sev.c | 14 ++- + migration/ram.c | 87 ++++++++++++++++++++++ + target/i386/csv.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 22 ++++++ + target/i386/sev.c | 14 +++- target/i386/sev.h | 1 + target/i386/trace-events | 1 + 6 files changed, 308 insertions(+), 1 deletion(-) diff --git a/migration/ram.c b/migration/ram.c -index 198b06000..71353bc90 100644 +index 198b060..71353bc 100644 --- a/migration/ram.c +++ b/migration/ram.c -@@ -2478,6 +2478,90 @@ ram_save_encrypted_pages_in_batch(RAMState *rs, PageSearchStatus *pss) - } +@@ -2479,6 +2479,90 @@ ram_save_encrypted_pages_in_batch(RAMState *rs, PageSearchStatus *pss) #endif -+/** + /** + * ram_save_csv3_pages - send the given csv3 VM pages to the stream + */ +static int ram_save_csv3_pages(RAMState *rs, PageSearchStatus *pss) @@ -114,9 +113,10 @@ index 198b06000..71353bc90 100644 + return pages; +} + - /** ++/** * ram_save_host_page: save a whole host page * + * Starting at *offset send pages up to the end of the current host @@ -2513,6 +2597,9 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss) return 0; } @@ -128,7 +128,7 @@ index 198b06000..71353bc90 100644 /* * If command_batch function is enabled and memory encryption is enabled diff --git a/target/i386/csv.c b/target/i386/csv.c -index 5823c8994..ffa5a73a7 100644 +index 5823c89..ffa5a73 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -16,8 +16,13 @@ @@ -343,7 +343,7 @@ index 5823c8994..ffa5a73a7 100644 + return csv3_send_encrypt_data(s, f, NULL, 0, bytes_sent); +} diff --git a/target/i386/csv.h b/target/i386/csv.h -index 0c402cefd..e808bea61 100644 +index 0c402ce..e808bea 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -80,6 +80,18 @@ struct dma_map_region { @@ -394,7 +394,7 @@ index 0c402cefd..e808bea61 100644 #endif diff --git a/target/i386/sev.c b/target/i386/sev.c -index eb1026b57..465b62cb7 100644 +index eb1026b..465b62c 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -1225,7 +1225,11 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) @@ -429,7 +429,7 @@ index eb1026b57..465b62cb7 100644 static void diff --git a/target/i386/sev.h b/target/i386/sev.h -index e91431e0f..8ccef22a9 100644 +index e91431e..8ccef22 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -83,6 +83,7 @@ extern bool sev_kvm_has_msr_ghcb; @@ -441,7 +441,7 @@ index e91431e0f..8ccef22a9 100644 extern struct sev_ops sev_ops; diff --git a/target/i386/trace-events b/target/i386/trace-events -index e07061bf3..6ebb644cb 100644 +index e07061b..6ebb644 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -22,3 +22,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int @@ -450,5 +450,5 @@ index e07061bf3..6ebb644cb 100644 kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 +kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" -- -2.31.1 +1.8.3.1 diff --git a/1044-target-i386-csv-Add-support-to-migrate-the-incoming-.patch b/0228-target-i386-csv-Add-support-to-migrate-the-incoming-.patch similarity index 94% rename from 1044-target-i386-csv-Add-support-to-migrate-the-incoming-.patch rename to 0228-target-i386-csv-Add-support-to-migrate-the-incoming-.patch index 306d8e2f46f9b2b16910ef92340333ee98ef108d..b46b9e719856fcfeb998a115b245f60b49864703 100644 --- a/1044-target-i386-csv-Add-support-to-migrate-the-incoming-.patch +++ b/0228-target-i386-csv-Add-support-to-migrate-the-incoming-.patch @@ -1,7 +1,7 @@ -From e1ed25546ed0c9b1ae43c99131ef7910db6d03eb Mon Sep 17 00:00:00 2001 +From 3079e7490ee07f78222de62f16e1ba350cf2b0b4 Mon Sep 17 00:00:00 2001 From: jiangxin Date: Fri, 17 Jun 2022 09:45:45 +0800 -Subject: [PATCH 12/14] target/i386: csv: Add support to migrate the incoming +Subject: [PATCH 238/293] target/i386: csv: Add support to migrate the incoming page for CSV3 guest The csv3_receive_encrypt_data() provides the method to read incoming @@ -15,15 +15,15 @@ command is performed to the firmware. Signed-off-by: Jiang Xin Signed-off-by: hanliyang --- - target/i386/csv.c | 87 ++++++++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 2 + - target/i386/sev.c | 8 ++++ + target/i386/csv.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 2 ++ + target/i386/sev.c | 8 +++++ target/i386/sev.h | 1 + target/i386/trace-events | 1 + 5 files changed, 99 insertions(+) diff --git a/target/i386/csv.c b/target/i386/csv.c -index ffa5a73a7..81407e3c2 100644 +index ffa5a73..81407e3 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -38,11 +38,14 @@ bool csv_kvm_cpu_reset_inhibit; @@ -137,7 +137,7 @@ index ffa5a73a7..81407e3c2 100644 + return csv3_receive_encrypt_data(f, ptr); +} diff --git a/target/i386/csv.h b/target/i386/csv.h -index e808bea61..b0adae0a8 100644 +index e808bea..b0adae0 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -107,6 +107,7 @@ struct Csv3GuestState { @@ -157,7 +157,7 @@ index e808bea61..b0adae0a8 100644 int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); diff --git a/target/i386/sev.c b/target/i386/sev.c -index 465b62cb7..337f54415 100644 +index 465b62c..337f544 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -2619,10 +2619,18 @@ static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent) @@ -180,7 +180,7 @@ index 465b62cb7..337f54415 100644 static void diff --git a/target/i386/sev.h b/target/i386/sev.h -index 8ccef22a9..647b426b1 100644 +index 8ccef22..647b426 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -84,6 +84,7 @@ struct sev_ops { @@ -192,7 +192,7 @@ index 8ccef22a9..647b426b1 100644 extern struct sev_ops sev_ops; diff --git a/target/i386/trace-events b/target/i386/trace-events -index 6ebb644cb..9609fe3d5 100644 +index 6ebb644..9609fe3 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -23,3 +23,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int @@ -201,5 +201,5 @@ index 6ebb644cb..9609fe3d5 100644 kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" +kvm_csv3_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" -- -2.31.1 +1.8.3.1 diff --git a/1045-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch b/0229-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch similarity index 94% rename from 1045-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch rename to 0229-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch index 3bfdb71f8568c772cf2ae359833a750abb1b9d5b..642dac6e61f398423fc106e5f288cf0fcae7fe01 100644 --- a/1045-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch +++ b/0229-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch @@ -1,7 +1,7 @@ -From 434ad630110cd376ea184a11572ec72961e679a4 Mon Sep 17 00:00:00 2001 +From 709d9a2bbbde08209c706ee17351d4a6028fff1f Mon Sep 17 00:00:00 2001 From: jiangxin Date: Fri, 17 Jun 2022 09:52:31 +0800 -Subject: [PATCH 13/14] target/i386: csv: Add support to migrate the outgoing +Subject: [PATCH 239/293] target/i386: csv: Add support to migrate the outgoing context for CSV3 guest CSV3 needs to migrate guest cpu's context pages. Prior to migration @@ -12,13 +12,13 @@ RAM_SAVE_ENCRYPTED_CSV3_CONTEXT is defined for CSV3. Signed-off-by: Jiang Xin Signed-off-by: hanliyang --- - target/i386/csv.c | 81 ++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ target/i386/csv.h | 1 + target/i386/trace-events | 1 + 3 files changed, 83 insertions(+) diff --git a/target/i386/csv.c b/target/i386/csv.c -index 81407e3c2..1560db680 100644 +index 81407e3..1560db6 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -46,6 +46,7 @@ struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { @@ -114,7 +114,7 @@ index 81407e3c2..1560db680 100644 + return csv3_send_encrypt_context(s, f, bytes_sent); +} diff --git a/target/i386/csv.h b/target/i386/csv.h -index b0adae0a8..e9b8e00c9 100644 +index b0adae0..e9b8e00 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -124,5 +124,6 @@ void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); @@ -125,7 +125,7 @@ index b0adae0a8..e9b8e00c9 100644 #endif diff --git a/target/i386/trace-events b/target/i386/trace-events -index 9609fe3d5..31a2418bb 100644 +index 9609fe3..31a2418 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -23,4 +23,5 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int @@ -135,5 +135,5 @@ index 9609fe3d5..31a2418bb 100644 +kvm_csv3_send_encrypt_context(void *dst, int len) "trans %p len %d" kvm_csv3_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" -- -2.31.1 +1.8.3.1 diff --git a/1046-target-i386-csv-Add-support-to-migrate-the-incoming-.patch b/0230-target-i386-csv-Add-support-to-migrate-the-incoming-.patch similarity index 93% rename from 1046-target-i386-csv-Add-support-to-migrate-the-incoming-.patch rename to 0230-target-i386-csv-Add-support-to-migrate-the-incoming-.patch index f23e7401b31d99cbca69df0fd0df989fda0ce554..5608124b1c3404ef68dc143e4c71de6eec892227 100644 --- a/1046-target-i386-csv-Add-support-to-migrate-the-incoming-.patch +++ b/0230-target-i386-csv-Add-support-to-migrate-the-incoming-.patch @@ -1,7 +1,7 @@ -From e944da634c51c78e5fad793096c9ceba04ba3f19 Mon Sep 17 00:00:00 2001 +From 54e03311a01d11debdd264930c790564bdb61381 Mon Sep 17 00:00:00 2001 From: jiangxin Date: Fri, 17 Jun 2022 10:00:46 +0800 -Subject: [PATCH 14/14] target/i386: csv: Add support to migrate the incoming +Subject: [PATCH 240/293] target/i386: csv: Add support to migrate the incoming context for CSV3 guest The csv3_load_incoming_context() provides the method to read incoming @@ -12,13 +12,13 @@ performed by then to complete the whole migration. Signed-off-by: Jiang Xin Signed-off-by: hanliyang --- - target/i386/csv.c | 45 ++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ target/i386/csv.h | 1 + target/i386/trace-events | 1 + 3 files changed, 47 insertions(+) diff --git a/target/i386/csv.c b/target/i386/csv.c -index 1560db680..0593f9b19 100644 +index 1560db6..0593f9b 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -47,6 +47,7 @@ struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { @@ -85,7 +85,7 @@ index 1560db680..0593f9b19 100644 + return csv3_receive_encrypt_context(s, f); +} diff --git a/target/i386/csv.h b/target/i386/csv.h -index e9b8e00c9..bbe372498 100644 +index e9b8e00..bbe3724 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -122,6 +122,7 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); @@ -97,7 +97,7 @@ index e9b8e00c9..bbe372498 100644 int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent); diff --git a/target/i386/trace-events b/target/i386/trace-events -index 31a2418bb..515441c4f 100644 +index 31a2418..515441c 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -25,3 +25,4 @@ kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" P @@ -106,5 +106,5 @@ index 31a2418bb..515441c4f 100644 kvm_csv3_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" +kvm_csv3_receive_encrypt_context(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" -- -2.31.1 +1.8.3.1 diff --git a/1047-target-i386-sev-Fix-incompatibility-between-SEV-and-.patch b/0231-target-i386-sev-Fix-incompatibility-between-SEV-and-.patch similarity index 85% rename from 1047-target-i386-sev-Fix-incompatibility-between-SEV-and-.patch rename to 0231-target-i386-sev-Fix-incompatibility-between-SEV-and-.patch index 111042e113d7f6b4da8b00563a599e3f1fb3cdd3..352ddf01b76e9926f1492aa83a8f222862a1f3c5 100644 --- a/1047-target-i386-sev-Fix-incompatibility-between-SEV-and-.patch +++ b/0231-target-i386-sev-Fix-incompatibility-between-SEV-and-.patch @@ -1,8 +1,8 @@ -From 07177f6d3928d81a0c604df28efe4ac99ff96572 Mon Sep 17 00:00:00 2001 +From 4130a65b96413c814cf32b7d4d72dbf523796a86 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Fri, 1 Mar 2024 14:12:44 +0800 -Subject: [PATCH 1/2] target/i386: sev: Fix incompatibility between SEV and CSV - on the GET_ID API +Subject: [PATCH 241/293] target/i386: sev: Fix incompatibility between SEV and + CSV on the GET_ID API If the length of GET_ID request is too small, Hygon CSV will return SEV_RET_INVALID_PARAM. This return code doesn't comply with SEV API @@ -19,7 +19,7 @@ Change-Id: I204e69817fbb97c6c81bea086af53d4c312895b4 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/i386/sev.c b/target/i386/sev.c -index 337f54415..95b16cc63 100644 +index 337f544..95b16cc 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -589,7 +589,8 @@ static int sev_get_cpu0_id(int fd, guchar **id, size_t *id_len, Error **errp) @@ -33,5 +33,5 @@ index 337f54415..95b16cc63 100644 r, err, fw_error_to_str(err)); return 1; -- -2.31.1 +1.8.3.1 diff --git a/1048-target-i386-sev-Add-support-for-reuse-ASID-for-diffe.patch b/0232-target-i386-sev-Add-support-for-reuse-ASID-for-diffe.patch similarity index 92% rename from 1048-target-i386-sev-Add-support-for-reuse-ASID-for-diffe.patch rename to 0232-target-i386-sev-Add-support-for-reuse-ASID-for-diffe.patch index 8ff070eea07f9376911bac6a8c3f7c61f51aeef9..894de2dbe57ebe44115bb3df919e6ed2d162c793 100644 --- a/1048-target-i386-sev-Add-support-for-reuse-ASID-for-diffe.patch +++ b/0232-target-i386-sev-Add-support-for-reuse-ASID-for-diffe.patch @@ -1,7 +1,7 @@ -From 61c644ba560b8dd7fef2180633b0aa0cb1998fcd Mon Sep 17 00:00:00 2001 +From f49ae1db13f64cf331b357df888bbe01c90da72b Mon Sep 17 00:00:00 2001 From: appleLin Date: Wed, 3 Aug 2022 21:02:41 +0800 -Subject: [PATCH 2/2] target/i386: sev: Add support for reuse ASID for +Subject: [PATCH 242/293] target/i386: sev: Add support for reuse ASID for different CSV guests In you want to reuse one ASID for many CSV guests, you should provide a @@ -16,11 +16,11 @@ Change-Id: I929a7489b310f08535df67c231ee7b3cd9cee51e qapi/qom.json | 5 ++++- qemu-options.hx | 5 ++++- target/i386/csv.h | 5 +++-- - target/i386/sev.c | 47 ++++++++++++++++++++++++++++++++++++++- + target/i386/sev.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 6edf0b33a..f67a7dde1 100644 +index 6edf0b3..f67a7dd 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -2060,6 +2060,11 @@ struct kvm_csv_command_batch { @@ -36,7 +36,7 @@ index 6edf0b33a..f67a7dde1 100644 enum csv3_cmd_id { KVM_CSV3_NR_MIN = 0xc0, diff --git a/qapi/qom.json b/qapi/qom.json -index c53ef978f..89a2516b4 100644 +index c53ef97..89a2516 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -866,6 +866,8 @@ @@ -59,10 +59,10 @@ index c53ef978f..89a2516b4 100644 ## # @ThreadContextProperties: diff --git a/qemu-options.hx b/qemu-options.hx -index 42fd09e4d..0bc184cd0 100644 +index b6b4ad9..c260117 100644 --- a/qemu-options.hx +++ b/qemu-options.hx -@@ -5637,7 +5637,7 @@ SRST +@@ -5645,7 +5645,7 @@ SRST -object secret,id=sec0,keyid=secmaster0,format=base64,\\ data=$SECRET,iv=$(dh_cert_file = g_strdup(value); +@@ -374,6 +375,22 @@ sev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp) } -+static char * + static char * +sev_guest_get_user_id(Object *obj, Error **errp) +{ + SevGuestState *s = SEV_GUEST(obj); @@ -136,9 +135,10 @@ index 95b16cc63..68bf5da35 100644 + s->user_id = g_strdup(value); +} + - static char * ++static char * sev_guest_get_sev_device(Object *obj, Error **errp) { + SevGuestState *sev = SEV_GUEST(obj); @@ -426,6 +443,11 @@ sev_guest_class_init(ObjectClass *oc, void *data) sev_guest_set_kernel_hashes); object_class_property_set_description(oc, "kernel-hashes", @@ -184,5 +184,5 @@ index 95b16cc63..68bf5da35 100644 error_setg(errp, "%s: failed to initialize ret=%d fw_error=%d '%s'", __func__, ret, fw_error, fw_error_to_str(fw_error)); -- -2.31.1 +1.8.3.1 diff --git a/1049-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch b/0233-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch similarity index 82% rename from 1049-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch rename to 0233-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch index 1152322c62704603a7a926d85cd392606d55270b..29de8fd807fd5f2036908b55cfdc36c09ec2e568 100644 --- a/1049-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch +++ b/0233-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch @@ -1,7 +1,7 @@ -From 3c8add582393a03c9e85fdececc0e4cea229be54 Mon Sep 17 00:00:00 2001 +From 77dff465daa65a3dac8f0987fe08162d80a78fc1 Mon Sep 17 00:00:00 2001 From: Yanjing Zhou Date: Tue, 16 Apr 2024 15:27:33 +0800 -Subject: [PATCH 1/2] target/i386: Add Hygon Dhyana-v3 CPU model +Subject: [PATCH 243/293] target/i386: Add Hygon Dhyana-v3 CPU model Add the following feature bits for Dhyana CPU model: perfctr-core, clzero, xsaveerptr, aes, pclmulqdq, sha-ni @@ -14,10 +14,10 @@ Signed-off-by: Yanjing Zhou 1 file changed, 14 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index c01943ee6..1da8732c3 100644 +index a373d8e..61f81ad 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c -@@ -4658,6 +4658,20 @@ static const X86CPUDefinition builtin_x86_defs[] = { +@@ -4805,6 +4805,20 @@ static const X86CPUDefinition builtin_x86_defs[] = { { /* end of list */ } }, }, @@ -39,5 +39,5 @@ index c01943ee6..1da8732c3 100644 } }, -- -2.41.0 +1.8.3.1 diff --git a/1050-target-i386-Add-new-Hygon-Dharma-CPU-model.patch b/0234-target-i386-Add-new-Hygon-Dharma-CPU-model.patch similarity index 94% rename from 1050-target-i386-Add-new-Hygon-Dharma-CPU-model.patch rename to 0234-target-i386-Add-new-Hygon-Dharma-CPU-model.patch index 2ed71535c8b19893980499c60db413f471adbf38..8fd1626a2e973d554b9ac77664cdf93a975a68f4 100644 --- a/1050-target-i386-Add-new-Hygon-Dharma-CPU-model.patch +++ b/0234-target-i386-Add-new-Hygon-Dharma-CPU-model.patch @@ -1,18 +1,18 @@ -From 6e3d78f1f63f9a2c2dd3c50dc81af222822da99d Mon Sep 17 00:00:00 2001 +From 035ce0bc5b3f6e1621bd11fbc9218dba8ee88fc9 Mon Sep 17 00:00:00 2001 From: Yanjing Zhou Date: Tue, 16 Apr 2024 16:05:00 +0800 -Subject: [PATCH 2/2] target/i386: Add new Hygon 'Dharma' CPU model +Subject: [PATCH 244/293] target/i386: Add new Hygon 'Dharma' CPU model Add the following feature bits compare to Dhyana CPU model: stibp, ibrs, umip, ssbd Signed-off-by: Yanjing Zhou --- - target/i386/cpu.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++ + target/i386/cpu.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 1da8732c3..ce0c0bd49 100644 +index 61f81ad..8649f9e 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2163,6 +2163,56 @@ static const CPUCaches epyc_genoa_cache_info = { @@ -72,7 +72,7 @@ index 1da8732c3..ce0c0bd49 100644 /* The following VMX features are not supported by KVM and are left out in the * CPU definitions: * -@@ -4903,6 +4953,55 @@ static const X86CPUDefinition builtin_x86_defs[] = { +@@ -5050,6 +5100,55 @@ static const X86CPUDefinition builtin_x86_defs[] = { .model_id = "AMD EPYC-Genoa Processor", .cache_info = &epyc_genoa_cache_info, }, @@ -129,5 +129,5 @@ index 1da8732c3..ce0c0bd49 100644 /* -- -2.41.0 +1.8.3.1 diff --git a/0235-vfio-Add-vfio-based-mediated-hct-support.patch b/0235-vfio-Add-vfio-based-mediated-hct-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..2fcbf5d80f4911d7f95eebdd96a75e43ee9dcabf --- /dev/null +++ b/0235-vfio-Add-vfio-based-mediated-hct-support.patch @@ -0,0 +1,591 @@ +From ca383d757fa3a1bd6f0af2d82555502e0fd75e4b Mon Sep 17 00:00:00 2001 +From: Yabin Li +Date: Fri, 4 Aug 2023 21:09:08 +0800 +Subject: [PATCH 245/293] vfio: Add vfio based mediated hct support. + +add device hct used for simulate hygon ccp + +Signed-off-by: liyabin +Signed-off-by: yangdepei +Change-Id: I8606ad46b4fa3671233597e89c14589b96a9081b +--- + hw/vfio/Kconfig | 6 + + hw/vfio/hct.c | 540 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + hw/vfio/meson.build | 1 + + 3 files changed, 547 insertions(+) + create mode 100644 hw/vfio/hct.c + +diff --git a/hw/vfio/Kconfig b/hw/vfio/Kconfig +index 7cdba05..5f0d3c2 100644 +--- a/hw/vfio/Kconfig ++++ b/hw/vfio/Kconfig +@@ -41,3 +41,9 @@ config VFIO_IGD + bool + default y if PC_PCI + depends on VFIO_PCI ++ ++config VFIO_HCT ++ bool ++ default y ++ select VFIO ++ depends on LINUX && PCI +diff --git a/hw/vfio/hct.c b/hw/vfio/hct.c +new file mode 100644 +index 0000000..fb42927 +--- /dev/null ++++ b/hw/vfio/hct.c +@@ -0,0 +1,540 @@ ++/* ++ * vfio based mediated ccp(hct) assignment support ++ * ++ * Copyright 2023 HYGON Corp. ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or (at ++ * your option) any later version. See the COPYING file in the top-level ++ * directory. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "qemu/osdep.h" ++#include "qemu/queue.h" ++#include "qemu/main-loop.h" ++#include "qemu/log.h" ++#include "trace.h" ++#include "hw/pci/pci.h" ++#include "hw/vfio/pci.h" ++#include "qemu/range.h" ++#include "sysemu/kvm.h" ++#include "hw/pci/msi.h" ++#include "qemu/error-report.h" ++#include "qapi/error.h" ++#include "hw/qdev-properties.h" ++ ++#define MAX_CCP_CNT 48 ++#define PAGE_SIZE 4096 ++#define HCT_SHARED_MEMORY_SIZE (PAGE_SIZE * MAX_CCP_CNT) ++#define CCP_INDEX_BYTES 4 ++#define PATH_MAX 4096 ++#define TYPE_HCT_DEV "hct" ++#define PCI_HCT_DEV(obj) OBJECT_CHECK(HCTDevState, (obj), TYPE_HCT_DEV) ++#define HCT_MMIO_SIZE (1 << 20) ++#define HCT_MAX_PASID (1 << 8) ++ ++#define PCI_VENDOR_ID_HYGON_CCP 0x1d94 ++#define PCI_DEVICE_ID_HYGON_CCP 0x1468 ++ ++#define HCT_SHARE_DEV "/dev/hct_share" ++ ++#define HCT_VERSION_STRING "0.5" ++#define DEF_VERSION_STRING "0.1" ++#define VERSION_SIZE 16 ++ ++#define HCT_SHARE_IOC_TYPE 'C' ++#define HCT_SHARE_OP_TYPE 0x01 ++#define HCT_SHARE_OP _IOWR(HCT_SHARE_IOC_TYPE, \ ++ HCT_SHARE_OP_TYPE, \ ++ struct hct_dev_ctrl) ++#define HCT_SHARE_OP_DMA_MAP 0x01 ++#define HCT_SHARE_OP_GET_ID 0x03 ++#define HCT_SHARE_OP_GET_PASID 0x04 ++#define HCT_SHARE_OP_DMA_UNMAP 0x05 ++#define HCT_SHARE_OP_GET_VERSION 0x06 ++ ++/* BARS */ ++#define HCT_REG_BAR_IDX 2 ++#define HCT_SHARED_BAR_IDX 3 ++#define HCT_PASID_BAR_IDX 4 ++ ++#define PASID_OFFSET 40 ++ ++static volatile struct hct_data { ++ int init; ++ int hct_fd; ++ unsigned long pasid; ++ uint8_t *pasid_memory; ++ uint8_t *hct_shared_memory; ++ uint8_t ccp_index[MAX_CCP_CNT]; ++ uint8_t ccp_cnt; ++} hct_data; ++ ++typedef struct SharedDevice { ++ PCIDevice dev; ++ int shared_memory_offset; ++} SharedDevice; ++ ++typedef struct HctDevState { ++ SharedDevice sdev; ++ VFIODevice vdev; ++ MemoryRegion mmio; ++ MemoryRegion shared; ++ MemoryRegion pasid; ++ void *maps[PCI_NUM_REGIONS]; ++} HCTDevState; ++ ++struct hct_dev_ctrl { ++ unsigned char op; ++ unsigned char rsvd[3]; ++ union { ++ unsigned char version[VERSION_SIZE]; ++ struct { ++ unsigned long vaddr; ++ unsigned long iova; ++ unsigned long size; ++ }; ++ unsigned int id; ++ }; ++}; ++ ++static int pasid_get_and_init(HCTDevState *state) ++{ ++ struct hct_dev_ctrl ctrl; ++ int ret; ++ ++ ctrl.op = HCT_SHARE_OP_GET_PASID; ++ ctrl.id = -1; ++ ret = ioctl(hct_data.hct_fd, HCT_SHARE_OP, &ctrl); ++ if (ret < 0) { ++ ret = -errno; ++ error_report("GET_PASID fail: %d", -errno); ++ goto out; ++ } ++ ++ *hct_data.pasid_memory = ctrl.id; ++ hct_data.pasid = ctrl.id; ++ ++out: ++ return ret; ++} ++ ++static const MemoryRegionOps hct_mmio_ops = { ++ .endianness = DEVICE_NATIVE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 4, ++ .max_access_size = 4, ++ }, ++}; ++ ++static void vfio_hct_detach_device(HCTDevState *state) ++{ ++ vfio_detach_device(&state->vdev); ++ g_free(state->vdev.name); ++} ++ ++static void vfio_hct_exit(PCIDevice *dev) ++{ ++ HCTDevState *state = PCI_HCT_DEV(dev); ++ ++ vfio_hct_detach_device(state); ++ ++ if (hct_data.hct_fd) { ++ qemu_close(hct_data.hct_fd); ++ hct_data.hct_fd = 0; ++ } ++} ++ ++static Property vfio_hct_properties[] = { ++ DEFINE_PROP_STRING("sysfsdev", HCTDevState, vdev.sysfsdev), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void vfio_ccp_compute_needs_reset(VFIODevice *vdev) ++{ ++ vdev->needs_reset = false; ++} ++ ++struct VFIODeviceOps vfio_ccp_ops = { ++ .vfio_compute_needs_reset = vfio_ccp_compute_needs_reset, ++}; ++ ++/* create BAR2, BAR3 and BAR4 space for the virtual machine. */ ++static int vfio_hct_region_mmap(HCTDevState *state) ++{ ++ int ret; ++ int i; ++ struct vfio_region_info *info; ++ ++ for (i = 0; i < PCI_ROM_SLOT; i++) { ++ ret = vfio_get_region_info(&state->vdev, i, &info); ++ if (ret) ++ goto out; ++ ++ if (info->size) { ++ state->maps[i] = mmap(NULL, info->size, PROT_READ | PROT_WRITE, ++ MAP_SHARED, state->vdev.fd, info->offset); ++ if (state->maps[i] == MAP_FAILED) { ++ ret = -errno; ++ g_free(info); ++ error_report("vfio mmap fail\n"); ++ goto out; ++ } ++ } ++ g_free(info); ++ } ++ ++ memory_region_init_io(&state->mmio, OBJECT(state), &hct_mmio_ops, state, ++ "hct mmio", HCT_MMIO_SIZE); ++ memory_region_init_ram_device_ptr(&state->mmio, OBJECT(state), "hct mmio", ++ HCT_MMIO_SIZE, ++ state->maps[HCT_REG_BAR_IDX]); ++ ++ memory_region_init_io(&state->shared, OBJECT(state), &hct_mmio_ops, state, ++ "hct shared memory", PAGE_SIZE); ++ memory_region_init_ram_device_ptr( ++ &state->shared, OBJECT(state), "hct shared memory", PAGE_SIZE, ++ (void *)hct_data.hct_shared_memory + ++ state->sdev.shared_memory_offset * PAGE_SIZE); ++ ++ memory_region_init_io(&state->pasid, OBJECT(state), &hct_mmio_ops, state, ++ "hct pasid", PAGE_SIZE); ++ memory_region_init_ram_device_ptr(&state->pasid, OBJECT(state), "hct pasid", ++ PAGE_SIZE, hct_data.pasid_memory); ++ ++ pci_register_bar(&state->sdev.dev, HCT_REG_BAR_IDX, ++ PCI_BASE_ADDRESS_SPACE_MEMORY, &state->mmio); ++ pci_register_bar(&state->sdev.dev, HCT_SHARED_BAR_IDX, ++ PCI_BASE_ADDRESS_SPACE_MEMORY, &state->shared); ++ pci_register_bar(&state->sdev.dev, HCT_PASID_BAR_IDX, ++ PCI_BASE_ADDRESS_SPACE_MEMORY, &state->pasid); ++out: ++ return ret; ++} ++ ++static int hct_check_duplicated_index(int index) ++{ ++ int cnt; ++ for (cnt = 0; cnt < hct_data.ccp_cnt; cnt++) { ++ if (hct_data.ccp_index[cnt] == index) { ++ error_report("many mdev shouldn't be mapped to one ccp in a " ++ "virtual machine!\n"); ++ return -1; ++ } ++ } ++ ++ hct_data.ccp_index[hct_data.ccp_cnt++] = index; ++ return 0; ++} ++ ++static int hct_get_ccp_index(HCTDevState *state) ++{ ++ char path[PATH_MAX]; ++ char buf[CCP_INDEX_BYTES]; ++ int fd; ++ int ret; ++ int ccp_index; ++ ++ snprintf(path, PATH_MAX, "%s/vendor/id", state->vdev.sysfsdev); ++ fd = qemu_open_old(path, O_RDONLY); ++ if (fd < 0) { ++ error_report("open %s fail\n", path); ++ return -errno; ++ } ++ ++ ret = read(fd, buf, sizeof(buf)); ++ if (ret < 0) { ++ ret = -errno; ++ error_report("read %s fail\n", path); ++ goto out; ++ } ++ ++ if (1 != sscanf(buf, "%d", &ccp_index)) { ++ ret = -errno; ++ error_report("format addr %s fail\n", buf); ++ goto out; ++ } ++ ++ if (!hct_check_duplicated_index(ccp_index)) { ++ state->sdev.shared_memory_offset = ccp_index; ++ } else { ++ ret = -1; ++ } ++ ++out: ++ qemu_close(fd); ++ return ret; ++} ++ ++static int hct_api_version_check(void) ++{ ++ struct hct_dev_ctrl ctrl; ++ int ret; ++ ++ ctrl.op = HCT_SHARE_OP_GET_VERSION; ++ memcpy(ctrl.version, DEF_VERSION_STRING, sizeof(DEF_VERSION_STRING)); ++ ret = ioctl(hct_data.hct_fd, HCT_SHARE_OP, &ctrl); ++ if (ret < 0) { ++ error_report("ret %d, errno %d: fail to get hct.ko version.\n", ret, ++ errno); ++ return -1; ++ } else if (memcmp(ctrl.version, HCT_VERSION_STRING, ++ sizeof(HCT_VERSION_STRING)) < 0) { ++ error_report("The hct.ko version is %s, please upgrade to version %s " ++ "or higher.\n", ++ ctrl.version, HCT_VERSION_STRING); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int hct_shared_memory_init(void) ++{ ++ int ret = 0; ++ ++ hct_data.hct_shared_memory = ++ mmap(NULL, HCT_SHARED_MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, ++ hct_data.hct_fd, 0); ++ if (hct_data.hct_shared_memory == MAP_FAILED) { ++ ret = -errno; ++ error_report("map hct shared memory fail\n"); ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++static void hct_listener_region_add(MemoryListener *listener, ++ MemoryRegionSection *section) ++{ ++ struct hct_dev_ctrl ctrl; ++ hwaddr iova; ++ Int128 llend, llsize; ++ void *vaddr; ++ int ret; ++ ++ iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space); ++ llend = int128_make64(section->offset_within_address_space); ++ llend = int128_add(llend, section->size); ++ llend = int128_add(llend, int128_exts64(qemu_real_host_page_mask())); ++ ++ if (int128_ge(int128_make64(iova), llend)) { ++ return; ++ } ++ ++ if (!section->mr->ram) { ++ return; ++ } ++ ++ vaddr = memory_region_get_ram_ptr(section->mr) + ++ section->offset_within_region + ++ (iova - section->offset_within_address_space); ++ llsize = int128_sub(llend, int128_make64(iova)); ++ ++ ctrl.op = HCT_SHARE_OP_DMA_MAP; ++ ctrl.iova = iova | (hct_data.pasid << PASID_OFFSET); ++ ctrl.vaddr = (uint64_t)vaddr; ++ ctrl.size = llsize; ++ ret = ioctl(hct_data.hct_fd, HCT_SHARE_OP, &ctrl); ++ if (ret < 0) ++ error_report("VFIO_MAP_DMA: %d, iova=%lx", -errno, iova); ++} ++ ++static void hct_listener_region_del(MemoryListener *listener, ++ MemoryRegionSection *section) ++{ ++ struct hct_dev_ctrl ctrl; ++ hwaddr iova; ++ Int128 llend, llsize; ++ int ret; ++ ++ iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space); ++ llend = int128_make64(section->offset_within_address_space); ++ llend = int128_add(llend, section->size); ++ llend = int128_add(llend, int128_exts64(qemu_real_host_page_mask())); ++ ++ if (int128_ge(int128_make64(iova), llend)) { ++ return; ++ } ++ ++ if (!section->mr->ram) { ++ return; ++ } ++ ++ llsize = int128_sub(llend, int128_make64(iova)); ++ ++ ctrl.op = HCT_SHARE_OP_DMA_UNMAP; ++ ctrl.iova = iova | (hct_data.pasid << PASID_OFFSET); ++ ctrl.size = llsize; ++ ret = ioctl(hct_data.hct_fd, HCT_SHARE_OP, &ctrl); ++ if (ret < 0) ++ error_report("VFIO_UNMAP_DMA: %d", -errno); ++} ++ ++static MemoryListener hct_memory_listener = { ++ .region_add = hct_listener_region_add, ++ .region_del = hct_listener_region_del, ++}; ++ ++static void hct_data_uninit(HCTDevState *state) ++{ ++ if (hct_data.hct_fd) { ++ qemu_close(hct_data.hct_fd); ++ hct_data.hct_fd = 0; ++ } ++ ++ if (hct_data.pasid) { ++ hct_data.pasid = 0; ++ } ++ ++ if (hct_data.pasid_memory) { ++ munmap(hct_data.pasid_memory, PAGE_SIZE); ++ hct_data.pasid_memory = NULL; ++ } ++ ++ if (hct_data.hct_shared_memory) { ++ munmap((void *)hct_data.hct_shared_memory, HCT_SHARED_MEMORY_SIZE); ++ hct_data.hct_shared_memory = NULL; ++ } ++ ++ memory_listener_unregister(&hct_memory_listener); ++} ++ ++static int hct_data_init(HCTDevState *state) ++{ ++ int ret; ++ ++ if (hct_data.init == 0) { ++ ++ hct_data.hct_fd = qemu_open_old(HCT_SHARE_DEV, O_RDWR); ++ if (hct_data.hct_fd < 0) { ++ error_report("fail to open %s, errno %d.", HCT_SHARE_DEV, errno); ++ ret = -errno; ++ goto out; ++ } ++ ++ /* The hct.ko version number needs not to be less than 0.2. */ ++ ret = hct_api_version_check(); ++ if (ret) ++ goto out; ++ ++ /* assign a page to the virtual BAR3 of each CCP. */ ++ ret = hct_shared_memory_init(); ++ if (ret) ++ goto out; ++ ++ hct_data.pasid_memory = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ if (hct_data.pasid_memory < 0) ++ goto unmap_shared_memory_exit; ++ ++ /* assign a unique pasid to each virtual machine. */ ++ ret = pasid_get_and_init(state); ++ if (ret < 0) ++ goto unmap_pasid_memory_exit; ++ ++ /* perform DMA_MAP and DMA_UNMAP operations on all memories of the ++ * virtual machine. */ ++ memory_listener_register(&hct_memory_listener, &address_space_memory); ++ ++ hct_data.init = 1; ++ } ++ ++ return hct_get_ccp_index(state); ++ ++unmap_pasid_memory_exit: ++ munmap(hct_data.pasid_memory, PAGE_SIZE); ++ ++unmap_shared_memory_exit: ++ munmap((void *)hct_data.hct_shared_memory, HCT_SHARED_MEMORY_SIZE); ++ ++out: ++ return ret; ++} ++ ++/* When device is loaded */ ++static void vfio_hct_realize(PCIDevice *pci_dev, Error **errp) ++{ ++ int ret; ++ char *mdevid; ++ Error *err = NULL; ++ HCTDevState *state = PCI_HCT_DEV(pci_dev); ++ ++ /* parsing mdev device name from startup scripts */ ++ mdevid = g_path_get_basename(state->vdev.sysfsdev); ++ state->vdev.name = g_strdup_printf("%s", mdevid); ++ ++ ret = hct_data_init(state); ++ if (ret < 0) { ++ g_free(state->vdev.name); ++ goto out; ++ } ++ ++ ret = vfio_attach_device(state->vdev.name, &state->vdev, ++ pci_device_iommu_address_space(pci_dev), &err); ++ ++ if (ret) { ++ error_report("attach device failed, name = %s", state->vdev.name); ++ goto data_uninit_out; ++ } ++ ++ state->vdev.ops = &vfio_ccp_ops; ++ state->vdev.dev = &state->sdev.dev.qdev; ++ ++ ret = vfio_hct_region_mmap(state); ++ if (ret < 0) ++ goto detach_device_out; ++ ++ return; ++ ++detach_device_out: ++ vfio_hct_detach_device(state); ++ ++data_uninit_out: ++ hct_data_uninit(state); ++ ++out: ++ return; ++} ++ ++static void hct_dev_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass); ++ ++ dc->desc = "HCT Device"; ++ device_class_set_props(dc, vfio_hct_properties); ++ ++ pdc->realize = vfio_hct_realize; ++ pdc->exit = vfio_hct_exit; ++ pdc->vendor_id = PCI_VENDOR_ID_HYGON_CCP; ++ pdc->device_id = PCI_DEVICE_ID_HYGON_CCP; ++ pdc->class_id = PCI_CLASS_CRYPT_OTHER; ++ set_bit(DEVICE_CATEGORY_MISC, dc->categories); ++ ++ return; ++} ++ ++static const TypeInfo pci_hct_info = { ++ .name = TYPE_HCT_DEV, ++ .parent = TYPE_PCI_DEVICE, ++ .instance_size = sizeof(HCTDevState), ++ .class_init = hct_dev_class_init, ++ .interfaces = ++ (InterfaceInfo[]){ ++ {INTERFACE_CONVENTIONAL_PCI_DEVICE}, ++ {}, ++ }, ++}; ++ ++static void hct_register_types(void) { type_register_static(&pci_hct_info); } ++ ++type_init(hct_register_types); +diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build +index 2a6912c..b1db4c8 100644 +--- a/hw/vfio/meson.build ++++ b/hw/vfio/meson.build +@@ -17,5 +17,6 @@ vfio_ss.add(when: 'CONFIG_VFIO_XGMAC', if_true: files('calxeda-xgmac.c')) + vfio_ss.add(when: 'CONFIG_VFIO_AMD_XGBE', if_true: files('amd-xgbe.c')) + vfio_ss.add(when: 'CONFIG_VFIO_AP', if_true: files('ap.c')) + vfio_ss.add(when: 'CONFIG_VFIO_IGD', if_true: files('igd.c')) ++vfio_ss.add(when: 'CONFIG_VFIO_HCT', if_true: files('hct.c')) + + specific_ss.add_all(when: 'CONFIG_VFIO', if_true: vfio_ss) +-- +1.8.3.1 + diff --git a/0236-hw-net-virtio-net-Update-event-idx-if-guest-has-made.patch b/0236-hw-net-virtio-net-Update-event-idx-if-guest-has-made.patch new file mode 100644 index 0000000000000000000000000000000000000000..68fe5c5d44a4872df27940100145cbf6e8c7b7a7 --- /dev/null +++ b/0236-hw-net-virtio-net-Update-event-idx-if-guest-has-made.patch @@ -0,0 +1,31 @@ +From 5da94be3c83d1c4598d7d8fd061122db1df8db2a Mon Sep 17 00:00:00 2001 +From: eastmoutain <14304864+eastmoutain@user.noreply.gitee.com> +Date: Mon, 17 Jun 2024 10:00:46 +0800 +Subject: [PATCH 246/293] hw/net: virtio-net: Update event idx if guest has + made extra buffers during double check + +If guest has made some buffers available during double check, +but the total buffer size available is lower than @bufsize, +notify the guest with the latest available idx(event idx) +seen by the host. + +Signed-off-by: yangwencheng +--- + hw/net/virtio-net.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 73024ba..5b0d814 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1653,6 +1653,7 @@ static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) + if (virtio_queue_empty(q->rx_vq) || + (n->mergeable_rx_bufs && + !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { ++ virtio_queue_set_notification(q->rx_vq, 1); + return 0; + } + } +-- +1.8.3.1 + diff --git a/0237-target-i386-csv-Release-CSV3-shared-pages-after-unma.patch b/0237-target-i386-csv-Release-CSV3-shared-pages-after-unma.patch new file mode 100644 index 0000000000000000000000000000000000000000..f545bf8cb1ebbe1650adb52df9ff7f20bcca70f4 --- /dev/null +++ b/0237-target-i386-csv-Release-CSV3-shared-pages-after-unma.patch @@ -0,0 +1,130 @@ +From 78c9048df55f4d8791ef3c79dbf652f8b682cd12 Mon Sep 17 00:00:00 2001 +From: eastmoutain <14304864+eastmoutain@user.noreply.gitee.com> +Date: Mon, 20 May 2024 21:12:23 +0800 +Subject: [PATCH 247/293] target/i386: csv: Release CSV3 shared pages after + unmapping DMA + +The shared pages are created for Device DMA access, release them +once DMA mapping is removed. + +Signed-off-by: yangwencheng +--- + linux-headers/linux/kvm.h | 9 +++++++++ + target/i386/csv-sysemu-stub.c | 5 +++++ + target/i386/csv.c | 34 ++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 1 + + target/i386/kvm/kvm.c | 1 + + 5 files changed, 50 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index f67a7dd..36da75b 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2076,6 +2076,7 @@ enum csv3_cmd_id { + KVM_CSV3_SEND_ENCRYPT_CONTEXT, + KVM_CSV3_RECEIVE_ENCRYPT_DATA, + KVM_CSV3_RECEIVE_ENCRYPT_CONTEXT, ++ KVM_CSV3_HANDLE_MEMORY, + + KVM_CSV3_NR_MAX, + }; +@@ -2122,6 +2123,14 @@ struct kvm_csv3_receive_encrypt_context { + __u32 trans_len; + }; + ++#define KVM_CSV3_RELEASE_SHARED_MEMORY (0x0001) ++ ++struct kvm_csv3_handle_memory { ++ __u64 gpa; ++ __u32 num_pages; ++ __u32 opcode; ++}; ++ + #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) + #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) + #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index db22c29..f3224a0 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -39,3 +39,8 @@ void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end) + { + + } ++ ++void csv3_shared_region_relese(uint64_t gpa, uint32_t num_pages) ++{ ++ ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 0593f9b..a869cc2 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -268,6 +268,40 @@ end: + return ret; + } + ++void csv3_shared_region_release(uint64_t gpa, uint32_t num_pages) ++{ ++ struct kvm_csv3_handle_memory mem = { 0 }; ++ MemoryRegion *mr = NULL; ++ void *hva; ++ int ret; ++ ++ if (!csv3_enabled()) ++ return; ++ ++ if (!gpa || !num_pages) ++ return; ++ ++ mem.gpa = (__u64)gpa; ++ mem.num_pages = (__u32)num_pages; ++ mem.opcode = (__u32)KVM_CSV3_RELEASE_SHARED_MEMORY; ++ ++ /* unpin the pages */ ++ ret = csv3_ioctl(KVM_CSV3_HANDLE_MEMORY, &mem, NULL); ++ if (ret <= 0) { ++ if (ret < 0) ++ error_report("%s: CSV3 unpin failed ret %d", __func__, ret); ++ return; ++ } ++ ++ /* drop the pages */ ++ hva = gpa2hva(&mr, gpa, num_pages << TARGET_PAGE_BITS, NULL); ++ if (hva) { ++ ret = madvise(hva, num_pages << TARGET_PAGE_BITS, MADV_DONTNEED); ++ if (ret) ++ error_report("%s: madvise failed %d", __func__, ret); ++ } ++} ++ + void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end) + { + MemoryRegionSection section; +diff --git a/target/i386/csv.h b/target/i386/csv.h +index e5e05d0..a32588a 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -122,6 +122,7 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + + int csv3_shared_region_dma_map(uint64_t start, uint64_t end); + void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); ++void csv3_shared_region_release(uint64_t gpa, uint32_t num_pages); + int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); + int csv3_load_incoming_context(QEMUFile *f); + int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 925f4f8..fdceecc 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -5027,6 +5027,7 @@ static int kvm_handle_exit_hypercall(X86CPU *cpu, struct kvm_run *run) + if (enc) { + sev_remove_shared_regions_list(gfn_start, gfn_end); + csv3_shared_region_dma_unmap(gpa, gfn_end << TARGET_PAGE_BITS); ++ csv3_shared_region_release(gpa, npages); + } else { + sev_add_shared_regions_list(gfn_start, gfn_end); + csv3_shared_region_dma_map(gpa, gfn_end << TARGET_PAGE_BITS); +-- +1.8.3.1 + diff --git a/0238-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch b/0238-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch new file mode 100644 index 0000000000000000000000000000000000000000..f791ecffb370b8168a46168a709b4ea50fa23749 --- /dev/null +++ b/0238-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch @@ -0,0 +1,339 @@ +From ffab93e9daccdbb7352b64a5a18346a978c302de Mon Sep 17 00:00:00 2001 +From: thomas +Date: Fri, 12 Jul 2024 11:10:53 +0800 +Subject: [PATCH 248/293] virtio-net: Fix network stall at the host side + waiting for kick + +Patch 06b12970174 ("virtio-net: fix network stall under load") +added double-check to test whether the available buffer size +can satisfy the request or not, in case the guest has added +some buffers to the avail ring simultaneously after the first +check. It will be lucky if the available buffer size becomes +okay after the double-check, then the host can send the packet +to the guest. If the buffer size still can't satisfy the request, +even if the guest has added some buffers, viritio-net would +stall at the host side forever. + +The patch enables notification and checks whether the guest has +added some buffers since last check of available buffers when +the available buffers are insufficient. If no buffer is added, +return false, else recheck the available buffers in the loop. +If the available buffers are sufficient, disable notification +and return true. + +Changes: +1. Change the return type of virtqueue_get_avail_bytes() from void + to int, it returns an opaque that represents the shadow_avail_idx + of the virtqueue on success, else -1 on error. +2. Add a new API: virtio_queue_enable_notification_and_check(), + it takes an opaque as input arg which is returned from + virtqueue_get_avail_bytes(). It enables notification firstly, + then checks whether the guest has added some buffers since + last check of available buffers or not by virtio_queue_poll(), + return ture if yes. + +The patch also reverts patch "06b12970174". +The patch also reverts patch +1052-hw-net-virtio-net-Update-event-idx-if-guest-has-made.patch. + +The case below can reproduce the stall. + + Guest 0 + +--------+ + | iperf | + ---------------> | server | + Host | +--------+ + +--------+ | ... + | iperf |---- + | client |---- Guest n + +--------+ | +--------+ + | | iperf | + ---------------> | server | + +--------+ + +Boot many guests from qemu with virtio network: + qemu ... -netdev tap,id=net_x \ + -device virtio-net-pci-non-transitional,\ + iommu_platform=on,mac=xx:xx:xx:xx:xx:xx,netdev=net_x + +Each guest acts as iperf server with commands below: + iperf3 -s -D -i 10 -p 8001 + iperf3 -s -D -i 10 -p 8002 + +The host as iperf client: + iperf3 -c guest_IP -p 8001 -i 30 -w 256k -P 20 -t 40000 + iperf3 -c guest_IP -p 8002 -i 30 -w 256k -P 20 -t 40000 + +After some time, the host loses connection to the guest, +the guest can send packet to the host, but can't receive +packet from the host. + +It's more likely to happen if SWIOTLB is enabled in the guest, +allocating and freeing bounce buffer takes some CPU ticks, +copying from/to bounce buffer takes more CPU ticks, compared +with that there is no bounce buffer in the guest. +Once the rate of producing packets from the host approximates +the rate of receiveing packets in the guest, the guest would +loop in NAPI. + + receive packets --- + | | + v | + free buf virtnet_poll + | | + v | + add buf to avail ring --- + | + | need kick the host? + | NAPI continues + v + receive packets --- + | | + v | + free buf virtnet_poll + | | + v | + add buf to avail ring --- + | + v + ... ... + +On the other hand, the host fetches free buf from avail +ring, if the buf in the avail ring is not enough, the +host notifies the guest the event by writing the avail +idx read from avail ring to the event idx of used ring, +then the host goes to sleep, waiting for the kick signal +from the guest. + +Once the guest finds the host is waiting for kick singal +(in virtqueue_kick_prepare_split()), it kicks the host. + +The host may stall forever at the sequences below: + + Host Guest + ------------ ----------- + fetch buf, send packet receive packet --- + ... ... | + fetch buf, send packet add buf | + ... add buf virtnet_poll + buf not enough avail idx-> add buf | + read avail idx add buf | + add buf --- + receive packet --- + write event idx ... | + wait for kick add buf virtnet_poll + ... | + --- + no more packet, exit NAPI + +In the first loop of NAPI above, indicated in the range of +virtnet_poll above, the host is sending packets while the +guest is receiving packets and adding buffers. + step 1: The buf is not enough, for example, a big packet + needs 5 buf, but the available buf count is 3. + The host read current avail idx. + step 2: The guest adds some buf, then checks whether the + host is waiting for kick signal, not at this time. + The used ring is not empty, the guest continues + the second loop of NAPI. + step 3: The host writes the avail idx read from avail + ring to used ring as event idx via + virtio_queue_set_notification(q->rx_vq, 1). + step 4: At the end of the second loop of NAPI, recheck + whether kick is needed, as the event idx in the + used ring written by the host is beyound the + range of kick condition, the guest will not + send kick signal to the host. + +Fixes: 06b12970174 ("virtio-net: fix network stall under load") +Cc: qemu-stable@nongnu.org +Signed-off-by: Wencheng Yang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +--- + hw/net/virtio-net.c | 29 +++++++++++---------- + hw/virtio/virtio.c | 64 +++++++++++++++++++++++++++++++++++++++++++--- + include/hw/virtio/virtio.h | 18 ++++++++++--- + 3 files changed, 91 insertions(+), 20 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 5b0d814..b6574f9 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1640,25 +1640,28 @@ static bool virtio_net_can_receive(NetClientState *nc) + + static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) + { ++ int opaque; ++ unsigned int in_bytes; + VirtIONet *n = q->n; +- if (virtio_queue_empty(q->rx_vq) || +- (n->mergeable_rx_bufs && +- !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { +- virtio_queue_set_notification(q->rx_vq, 1); +- +- /* To avoid a race condition where the guest has made some buffers +- * available after the above check but before notification was +- * enabled, check for available buffers again. +- */ +- if (virtio_queue_empty(q->rx_vq) || +- (n->mergeable_rx_bufs && +- !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { +- virtio_queue_set_notification(q->rx_vq, 1); ++ ++ while (virtio_queue_empty(q->rx_vq) || n->mergeable_rx_bufs) { ++ opaque = virtqueue_get_avail_bytes(q->rx_vq, &in_bytes, NULL, ++ bufsize, 0); ++ /* Buffer is enough, disable notifiaction */ ++ if (bufsize <= in_bytes) { ++ break; ++ } ++ ++ if (virtio_queue_enable_notification_and_check(q->rx_vq, opaque)) { ++ /* Guest has added some buffers, try again */ ++ continue; ++ } else { + return 0; + } + } + + virtio_queue_set_notification(q->rx_vq, 0); ++ + return 1; + } + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 356d690..09e2de6 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -744,6 +744,60 @@ int virtio_queue_empty(VirtQueue *vq) + } + } + ++static bool virtio_queue_split_poll(VirtQueue *vq, unsigned shadow_idx) ++{ ++ if (unlikely(!vq->vring.avail)) { ++ return false; ++ } ++ ++ return (uint16_t)shadow_idx != vring_avail_idx(vq); ++} ++ ++static bool virtio_queue_packed_poll(VirtQueue *vq, unsigned shadow_idx) ++{ ++ VRingPackedDesc desc; ++ VRingMemoryRegionCaches *caches; ++ ++ if (unlikely(!vq->vring.desc)) { ++ return false; ++ } ++ ++ caches = vring_get_region_caches(vq); ++ if (!caches) { ++ return false; ++ } ++ ++ vring_packed_desc_read(vq->vdev, &desc, &caches->desc, ++ shadow_idx, true); ++ ++ return is_desc_avail(desc.flags, vq->shadow_avail_wrap_counter); ++} ++ ++static bool virtio_queue_poll(VirtQueue *vq, unsigned shadow_idx) ++{ ++ if (virtio_device_disabled(vq->vdev)) { ++ return false; ++ } ++ ++ if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) { ++ return virtio_queue_packed_poll(vq, shadow_idx); ++ } else { ++ return virtio_queue_split_poll(vq, shadow_idx); ++ } ++} ++ ++bool virtio_queue_enable_notification_and_check(VirtQueue *vq, ++ int opaque) ++{ ++ virtio_queue_set_notification(vq, 1); ++ ++ if (opaque >= 0) { ++ return virtio_queue_poll(vq, (unsigned)opaque); ++ } else { ++ return false; ++ } ++} ++ + static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len) + { +@@ -1323,9 +1377,9 @@ err: + goto done; + } + +-void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, +- unsigned int *out_bytes, +- unsigned max_in_bytes, unsigned max_out_bytes) ++int virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, ++ unsigned int *out_bytes, unsigned max_in_bytes, ++ unsigned max_out_bytes) + { + uint16_t desc_size; + VRingMemoryRegionCaches *caches; +@@ -1358,7 +1412,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, + caches); + } + +- return; ++ return (int)vq->shadow_avail_idx; + err: + if (in_bytes) { + *in_bytes = 0; +@@ -1366,6 +1420,8 @@ err: + if (out_bytes) { + *out_bytes = 0; + } ++ ++ return -1; + } + + int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index c8f7285..d2f4ed1 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -270,9 +270,13 @@ void qemu_put_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, + VirtQueueElement *elem); + int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, + unsigned int out_bytes); +-void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, +- unsigned int *out_bytes, +- unsigned max_in_bytes, unsigned max_out_bytes); ++/** ++ * Return <0 on error or an opaque >=0 to pass to ++ * virtio_queue_enable_notification_and_check on success. ++ */ ++int virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, ++ unsigned int *out_bytes, unsigned max_in_bytes, ++ unsigned max_out_bytes); + + void virtio_notify_irqfd(VirtIODevice *vdev, VirtQueue *vq); + void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); +@@ -306,6 +310,14 @@ int virtio_queue_ready(VirtQueue *vq); + + int virtio_queue_empty(VirtQueue *vq); + ++/** ++ * Enable notification and check whether guest has added some ++ * buffers since last call to virtqueue_get_avail_bytes. ++ * ++ * @opaque: value returned from virtqueue_get_avail_bytes ++ */ ++bool virtio_queue_enable_notification_and_check(VirtQueue *vq, ++ int opaque); + /* Host binding interface. */ + + uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr); +-- +1.8.3.1 + diff --git a/0239-devel-8.2-Hygon-HCT-Fix-for-vfio-based-mediated-hct.patch b/0239-devel-8.2-Hygon-HCT-Fix-for-vfio-based-mediated-hct.patch new file mode 100644 index 0000000000000000000000000000000000000000..468a414b38a64cb220d76d19fc3b1bfe68879dde --- /dev/null +++ b/0239-devel-8.2-Hygon-HCT-Fix-for-vfio-based-mediated-hct.patch @@ -0,0 +1,28 @@ +From 7718d53612105ea2325a751af111d2136f0f37cf Mon Sep 17 00:00:00 2001 +From: Xingrui Yi +Date: Tue, 24 Sep 2024 14:11:51 +0800 +Subject: [PATCH 249/293] [devel-8.2][Hygon][HCT] Fix for vfio based mediated + hct + +Fix for vfio based mediated hct in index_value + +Signed-off-by: Mingkai Xu +--- + hw/vfio/hct.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/vfio/hct.c b/hw/vfio/hct.c +index fb42927..2f40bf5 100644 +--- a/hw/vfio/hct.c ++++ b/hw/vfio/hct.c +@@ -248,6 +248,7 @@ static int hct_get_ccp_index(HCTDevState *state) + return -errno; + } + ++ memset(buf, 0, sizeof(buf)); + ret = read(fd, buf, sizeof(buf)); + if (ret < 0) { + ret = -errno; +-- +1.8.3.1 + diff --git a/0240-update-to-qemu-9.1-with-directory-hw-loongarch.patch b/0240-update-to-qemu-9.1-with-directory-hw-loongarch.patch new file mode 100644 index 0000000000000000000000000000000000000000..018f19e008cf5664c3542e5c5cf6696ea48ba374 --- /dev/null +++ b/0240-update-to-qemu-9.1-with-directory-hw-loongarch.patch @@ -0,0 +1,2651 @@ +From bf153c2e1b3d171127307d2decd006fc5a5af230 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Thu, 19 Sep 2024 20:39:18 +0800 +Subject: [PATCH 250/293] update to qemu 9.1 with directory hw/loongarch + +Synchronize the upstream patch related to qemu 9.1 loongarch, +Since only loongarch related codes are updated, +not all codes can not be split into independent patches. +Here, loongarch related patches in the upstream patch are split +and merged into a large patch. + +Signed-off-by: Xianglai Li +--- + hw/loongarch/Kconfig | 2 +- + hw/loongarch/acpi-build.c | 178 ++++--- + hw/loongarch/boot.c | 339 +++++++++++++ + hw/loongarch/fw_cfg.c | 2 +- + hw/loongarch/fw_cfg.h | 2 +- + hw/loongarch/meson.build | 1 + + hw/loongarch/virt.c | 979 +++++++++++++++++++++---------------- + include/hw/intc/loongarch_extioi.h | 22 +- + include/hw/loongarch/boot.h | 119 +++++ + include/hw/loongarch/virt.h | 20 +- + include/hw/pci-host/ls7a.h | 11 +- + target/loongarch/cpu.h | 1 + + 12 files changed, 1154 insertions(+), 522 deletions(-) + create mode 100644 hw/loongarch/boot.c + create mode 100644 include/hw/loongarch/boot.h + +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index 5727efe..9fa8f82 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -2,9 +2,9 @@ config LOONGARCH_VIRT + bool + select PCI + select PCI_EXPRESS_GENERIC_BRIDGE +- imply VIRTIO_VGA + imply PCI_DEVICES + imply NVDIMM ++ imply TPM_TIS_SYSBUS + select SERIAL + select VIRTIO_PCI + select PLATFORM_BUS +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +index f990405..a41e4c2 100644 +--- a/hw/loongarch/acpi-build.c ++++ b/hw/loongarch/acpi-build.c +@@ -31,6 +31,7 @@ + + #include "hw/acpi/generic_event_device.h" + #include "hw/pci-host/gpex.h" ++#include "sysemu/sysemu.h" + #include "sysemu/tpm.h" + #include "hw/platform-bus.h" + #include "hw/acpi/aml-build.h" +@@ -105,14 +106,15 @@ build_facs(GArray *table_data) + + /* build MADT */ + static void +-build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams) ++build_madt(GArray *table_data, BIOSLinker *linker, ++ LoongArchVirtMachineState *lvms) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + MachineClass *mc = MACHINE_GET_CLASS(ms); + const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms); + int i, arch_id; +- AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id, +- .oem_table_id = lams->oem_table_id }; ++ AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lvms->oem_id, ++ .oem_table_id = lvms->oem_table_id }; + + acpi_table_begin(&table, table_data); + +@@ -165,13 +167,14 @@ static void + build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + { + int i, arch_id, node_id; +- uint64_t mem_len, mem_base; +- int nb_numa_nodes = machine->numa_state->num_nodes; +- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); +- MachineClass *mc = MACHINE_GET_CLASS(lams); ++ hwaddr len, base, gap; ++ NodeInfo *numa_info; ++ int nodes, nb_numa_nodes = machine->numa_state->num_nodes; ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); ++ MachineClass *mc = MACHINE_GET_CLASS(lvms); + const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine); +- AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id, +- .oem_table_id = lams->oem_table_id }; ++ AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lvms->oem_id, ++ .oem_table_id = lvms->oem_table_id }; + + acpi_table_begin(&table, table_data); + build_append_int_noprefix(table_data, 1, 4); /* Reserved */ +@@ -195,35 +198,44 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + } + +- /* Node0 */ +- build_srat_memory(table_data, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, +- 0, MEM_AFFINITY_ENABLED); +- mem_base = VIRT_HIGHMEM_BASE; +- if (!nb_numa_nodes) { +- mem_len = machine->ram_size - VIRT_LOWMEM_SIZE; +- } else { +- mem_len = machine->numa_state->nodes[0].node_mem - VIRT_LOWMEM_SIZE; ++ base = VIRT_LOWMEM_BASE; ++ gap = VIRT_LOWMEM_SIZE; ++ numa_info = machine->numa_state->nodes; ++ nodes = nb_numa_nodes; ++ if (!nodes) { ++ nodes = 1; + } +- if (mem_len) +- build_srat_memory(table_data, mem_base, mem_len, 0, MEM_AFFINITY_ENABLED); +- +- /* Node1 - Nodemax */ +- if (nb_numa_nodes) { +- mem_base += mem_len; +- for (i = 1; i < nb_numa_nodes; ++i) { +- if (machine->numa_state->nodes[i].node_mem > 0) { +- build_srat_memory(table_data, mem_base, +- machine->numa_state->nodes[i].node_mem, i, +- MEM_AFFINITY_ENABLED); +- mem_base += machine->numa_state->nodes[i].node_mem; +- } ++ ++ for (i = 0; i < nodes; i++) { ++ if (nb_numa_nodes) { ++ len = numa_info[i].node_mem; ++ } else { ++ len = machine->ram_size; ++ } ++ ++ /* ++ * memory for the node splited into two part ++ * lowram: [base, +gap) ++ * highram: [VIRT_HIGHMEM_BASE, +(len - gap)) ++ */ ++ if (len >= gap) { ++ build_srat_memory(table_data, base, gap, i, MEM_AFFINITY_ENABLED); ++ len -= gap; ++ base = VIRT_HIGHMEM_BASE; ++ gap = machine->ram_size - VIRT_LOWMEM_SIZE; ++ } ++ ++ if (len) { ++ build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED); ++ base += len; ++ gap -= len; + } + } + + if (machine->device_memory) { + build_srat_memory(table_data, machine->device_memory->base, + memory_region_size(&machine->device_memory->mr), +- nb_numa_nodes - 1, ++ nodes - 1, + MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); + } + +@@ -241,23 +253,27 @@ struct AcpiBuildState { + MemoryRegion *linker_mr; + } AcpiBuildState; + +-static void build_uart_device_aml(Aml *table) ++static void build_uart_device_aml(Aml *table, int index) + { + Aml *dev; + Aml *crs; + Aml *pkg0, *pkg1, *pkg2; +- uint32_t uart_irq = VIRT_UART_IRQ; +- +- Aml *scope = aml_scope("_SB"); +- dev = aml_device("COMA"); ++ Aml *scope; ++ uint32_t uart_irq; ++ uint64_t base; ++ ++ uart_irq = VIRT_UART_IRQ + index; ++ base = VIRT_UART_BASE + index * VIRT_UART_SIZE; ++ scope = aml_scope("_SB"); ++ dev = aml_device("COM%d", index); + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501"))); +- aml_append(dev, aml_name_decl("_UID", aml_int(0))); ++ aml_append(dev, aml_name_decl("_UID", aml_int(index))); + aml_append(dev, aml_name_decl("_CCA", aml_int(1))); + crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, +- 0, VIRT_UART_BASE, VIRT_UART_BASE + VIRT_UART_SIZE - 1, ++ 0, base, base + VIRT_UART_SIZE - 1, + 0, VIRT_UART_SIZE)); + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_SHARED, &uart_irq, 1)); +@@ -279,13 +295,13 @@ static void + build_la_ged_aml(Aml *dsdt, MachineState *machine) + { + uint32_t event; +- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + + build_ged_aml(dsdt, "\\_SB."GED_DEVICE, +- HOTPLUG_HANDLER(lams->acpi_ged), ++ HOTPLUG_HANDLER(lvms->acpi_ged), + VIRT_SCI_IRQ, AML_SYSTEM_MEMORY, + VIRT_GED_EVT_ADDR); +- event = object_property_get_uint(OBJECT(lams->acpi_ged), ++ event = object_property_get_uint(OBJECT(lvms->acpi_ged), + "ged-event", &error_abort); + if (event & ACPI_GED_MEM_HOTPLUG_EVT) { + build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL, +@@ -295,7 +311,7 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine) + acpi_dsdt_add_power_button(dsdt); + } + +-static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams) ++static void build_pci_device_aml(Aml *scope, LoongArchVirtMachineState *lvms) + { + struct GPEXConfig cfg = { + .mmio64.base = VIRT_PCI_MEM_BASE, +@@ -305,13 +321,13 @@ static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams) + .ecam.base = VIRT_PCI_CFG_BASE, + .ecam.size = VIRT_PCI_CFG_SIZE, + .irq = VIRT_GSI_BASE + VIRT_DEVICE_IRQS, +- .bus = lams->pci_bus, ++ .bus = lvms->pci_bus, + }; + + acpi_dsdt_add_gpex(scope, &cfg); + } + +-static void build_flash_aml(Aml *scope, LoongArchMachineState *lams) ++static void build_flash_aml(Aml *scope, LoongArchVirtMachineState *lvms) + { + Aml *dev, *crs; + MemoryRegion *flash_mem; +@@ -322,11 +338,11 @@ static void build_flash_aml(Aml *scope, LoongArchMachineState *lams) + hwaddr flash1_base; + hwaddr flash1_size; + +- flash_mem = pflash_cfi01_get_memory(lams->flash[0]); ++ flash_mem = pflash_cfi01_get_memory(lvms->flash[0]); + flash0_base = flash_mem->addr; + flash0_size = memory_region_size(flash_mem); + +- flash_mem = pflash_cfi01_get_memory(lams->flash[1]); ++ flash_mem = pflash_cfi01_get_memory(lvms->flash[1]); + flash1_base = flash_mem->addr; + flash1_size = memory_region_size(flash_mem); + +@@ -352,7 +368,7 @@ static void build_flash_aml(Aml *scope, LoongArchMachineState *lams) + } + + #ifdef CONFIG_TPM +-static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms) ++static void acpi_dsdt_add_tpm(Aml *scope, LoongArchVirtMachineState *vms) + { + PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev); + hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS; +@@ -390,19 +406,21 @@ static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms) + static void + build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) + { ++ int i; + Aml *dsdt, *scope, *pkg; +- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); +- AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id, +- .oem_table_id = lams->oem_table_id }; ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); ++ AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lvms->oem_id, ++ .oem_table_id = lvms->oem_table_id }; + + acpi_table_begin(&table, table_data); + dsdt = init_aml_allocator(); +- build_uart_device_aml(dsdt); +- build_pci_device_aml(dsdt, lams); ++ for (i = 0; i < VIRT_UART_COUNT; i++) ++ build_uart_device_aml(dsdt, i); ++ build_pci_device_aml(dsdt, lvms); + build_la_ged_aml(dsdt, machine); +- build_flash_aml(dsdt, lams); ++ build_flash_aml(dsdt, lvms); + #ifdef CONFIG_TPM +- acpi_dsdt_add_tpm(dsdt, lams); ++ acpi_dsdt_add_tpm(dsdt, lvms); + #endif + /* System State Package */ + scope = aml_scope("\\"); +@@ -421,7 +439,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) + + static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + GArray *table_offsets; + AcpiFadtData fadt_data; + unsigned facs, rsdt, dsdt; +@@ -455,28 +473,29 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + fadt_data.dsdt_tbl_offset = &dsdt; + fadt_data.xdsdt_tbl_offset = &dsdt; + build_fadt(tables_blob, tables->linker, &fadt_data, +- lams->oem_id, lams->oem_table_id); ++ lvms->oem_id, lvms->oem_table_id); + + acpi_add_table(table_offsets, tables_blob); +- build_madt(tables_blob, tables->linker, lams); ++ build_madt(tables_blob, tables->linker, lvms); + + acpi_add_table(table_offsets, tables_blob); + build_pptt(tables_blob, tables->linker, machine, +- lams->oem_id, lams->oem_table_id); ++ lvms->oem_id, lvms->oem_table_id); + + acpi_add_table(table_offsets, tables_blob); + build_srat(tables_blob, tables->linker, machine); ++ acpi_add_table(table_offsets, tables_blob); + + if (machine->numa_state->num_nodes) { + if (machine->numa_state->have_numa_distance) { + acpi_add_table(table_offsets, tables_blob); +- build_slit(tables_blob, tables->linker, machine, lams->oem_id, +- lams->oem_table_id); ++ build_slit(tables_blob, tables->linker, machine, lvms->oem_id, ++ lvms->oem_table_id); + } + if (machine->numa_state->hmat_enabled) { + acpi_add_table(table_offsets, tables_blob); + build_hmat(tables_blob, tables->linker, machine->numa_state, +- lams->oem_id, lams->oem_table_id); ++ lvms->oem_id, lvms->oem_table_id); + } + } + +@@ -486,8 +505,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + .base = cpu_to_le64(VIRT_PCI_CFG_BASE), + .size = cpu_to_le64(VIRT_PCI_CFG_SIZE), + }; +- build_mcfg(tables_blob, tables->linker, &mcfg, lams->oem_id, +- lams->oem_table_id); ++ build_mcfg(tables_blob, tables->linker, &mcfg, lvms->oem_id, ++ lvms->oem_table_id); + } + + #ifdef CONFIG_TPM +@@ -495,8 +514,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) { + acpi_add_table(table_offsets, tables_blob); + build_tpm2(tables_blob, tables->linker, +- tables->tcpalog, lams->oem_id, +- lams->oem_table_id); ++ tables->tcpalog, lvms->oem_id, ++ lvms->oem_table_id); + } + #endif + /* Add tables supplied by user (if any) */ +@@ -510,13 +529,13 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + /* RSDT is pointed to by RSDP */ + rsdt = tables_blob->len; + build_rsdt(tables_blob, tables->linker, table_offsets, +- lams->oem_id, lams->oem_table_id); ++ lvms->oem_id, lvms->oem_table_id); + + /* RSDP is in FSEG memory, so allocate it separately */ + { + AcpiRsdpData rsdp_data = { + .revision = 0, +- .oem_id = lams->oem_id, ++ .oem_id = lvms->oem_id, + .xsdt_tbl_offset = NULL, + .rsdt_tbl_offset = &rsdt, + }; +@@ -532,7 +551,7 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + " migration may not work", + tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2); + error_printf("Try removing CPUs, NUMA nodes, memory slots" +- " or PCI bridges."); ++ " or PCI bridges.\n"); + } + + acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE); +@@ -587,23 +606,31 @@ static const VMStateDescription vmstate_acpi_build = { + .name = "acpi_build", + .version_id = 1, + .minimum_version_id = 1, +- .fields = (VMStateField[]) { ++ .fields = (const VMStateField[]) { + VMSTATE_UINT8(patched, AcpiBuildState), + VMSTATE_END_OF_LIST() + }, + }; + +-void loongarch_acpi_setup(LoongArchMachineState *lams) ++static bool loongarch_is_acpi_enabled(LoongArchVirtMachineState *lvms) ++{ ++ if (lvms->acpi == ON_OFF_AUTO_OFF) { ++ return false; ++ } ++ return true; ++} ++ ++void loongarch_acpi_setup(LoongArchVirtMachineState *lvms) + { + AcpiBuildTables tables; + AcpiBuildState *build_state; + +- if (!lams->fw_cfg) { ++ if (!lvms->fw_cfg) { + ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); + return; + } + +- if (!loongarch_is_acpi_enabled(lams)) { ++ if (!loongarch_is_acpi_enabled(lvms)) { + ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n"); + return; + } +@@ -611,7 +638,7 @@ void loongarch_acpi_setup(LoongArchMachineState *lams) + build_state = g_malloc0(sizeof *build_state); + + acpi_build_tables_init(&tables); +- acpi_build(&tables, MACHINE(lams)); ++ acpi_build(&tables, MACHINE(lvms)); + + /* Now expose it all to Guest */ + build_state->table_mr = acpi_add_rom_blob(acpi_build_update, +@@ -627,6 +654,9 @@ void loongarch_acpi_setup(LoongArchMachineState *lams) + build_state, tables.rsdp, + ACPI_BUILD_RSDP_FILE); + ++ fw_cfg_add_file(lvms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, ++ acpi_data_len(tables.tcpalog)); ++ + qemu_register_reset(acpi_build_reset, build_state); + acpi_build_reset(build_state); + vmstate_register(NULL, 0, &vmstate_acpi_build, build_state); +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +new file mode 100644 +index 0000000..cb66870 +--- /dev/null ++++ b/hw/loongarch/boot.c +@@ -0,0 +1,339 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch boot helper functions. ++ * ++ * Copyright (c) 2023 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/units.h" ++#include "target/loongarch/cpu.h" ++#include "hw/loongarch/virt.h" ++#include "hw/loader.h" ++#include "elf.h" ++#include "qemu/error-report.h" ++#include "sysemu/reset.h" ++#include "sysemu/qtest.h" ++ ++struct memmap_entry *memmap_table; ++unsigned memmap_entries; ++ ++ram_addr_t initrd_offset; ++uint64_t initrd_size; ++ ++static const unsigned int slave_boot_code[] = { ++ /* Configure reset ebase. */ ++ 0x0400302c, /* csrwr $t0, LOONGARCH_CSR_EENTRY */ ++ ++ /* Disable interrupt. */ ++ 0x0380100c, /* ori $t0, $zero,0x4 */ ++ 0x04000180, /* csrxchg $zero, $t0, LOONGARCH_CSR_CRMD */ ++ ++ /* Clear mailbox. */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x038081ad, /* ori $t1, $t1, CORE_BUF_20 */ ++ 0x06481da0, /* iocsrwr.d $zero, $t1 */ ++ ++ /* Enable IPI interrupt. */ ++ 0x1400002c, /* lu12i.w $t0, 1(0x1) */ ++ 0x0400118c, /* csrxchg $t0, $t0, LOONGARCH_CSR_ECFG */ ++ 0x02fffc0c, /* addi.d $t0, $r0,-1(0xfff) */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x038011ad, /* ori $t1, $t1, CORE_EN_OFF */ ++ 0x064819ac, /* iocsrwr.w $t0, $t1 */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x038081ad, /* ori $t1, $t1, CORE_BUF_20 */ ++ ++ /* Wait for wakeup <.L11>: */ ++ 0x06488000, /* idle 0x0 */ ++ 0x03400000, /* andi $zero, $zero, 0x0 */ ++ 0x064809ac, /* iocsrrd.w $t0, $t1 */ ++ 0x43fff59f, /* beqz $t0, -12(0x7ffff4) # 48 <.L11> */ ++ ++ /* Read and clear IPI interrupt. */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x064809ac, /* iocsrrd.w $t0, $t1 */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x038031ad, /* ori $t1, $t1, CORE_CLEAR_OFF */ ++ 0x064819ac, /* iocsrwr.w $t0, $t1 */ ++ ++ /* Disable IPI interrupt. */ ++ 0x1400002c, /* lu12i.w $t0, 1(0x1) */ ++ 0x04001180, /* csrxchg $zero, $t0, LOONGARCH_CSR_ECFG */ ++ ++ /* Read mail buf and jump to specified entry */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x038081ad, /* ori $t1, $t1, CORE_BUF_20 */ ++ 0x06480dac, /* iocsrrd.d $t0, $t1 */ ++ 0x00150181, /* move $ra, $t0 */ ++ 0x4c000020, /* jirl $zero, $ra,0 */ ++}; ++ ++static inline void *guidcpy(void *dst, const void *src) ++{ ++ return memcpy(dst, src, sizeof(efi_guid_t)); ++} ++ ++static void init_efi_boot_memmap(struct efi_system_table *systab, ++ void *p, void *start) ++{ ++ unsigned i; ++ struct efi_boot_memmap *boot_memmap = p; ++ efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID; ++ ++ /* efi_configuration_table 1 */ ++ guidcpy(&systab->tables[0].guid, &tbl_guid); ++ systab->tables[0].table = (struct efi_configuration_table *)(p - start); ++ systab->nr_tables = 1; ++ ++ boot_memmap->desc_size = sizeof(efi_memory_desc_t); ++ boot_memmap->desc_ver = 1; ++ boot_memmap->map_size = 0; ++ ++ efi_memory_desc_t *map = p + sizeof(struct efi_boot_memmap); ++ for (i = 0; i < memmap_entries; i++) { ++ map = (void *)boot_memmap + sizeof(*map); ++ map[i].type = memmap_table[i].type; ++ map[i].phys_addr = ROUND_UP(memmap_table[i].address, 64 * KiB); ++ map[i].num_pages = ROUND_DOWN(memmap_table[i].address + ++ memmap_table[i].length - map[i].phys_addr, 64 * KiB); ++ p += sizeof(efi_memory_desc_t); ++ } ++} ++ ++static void init_efi_initrd_table(struct efi_system_table *systab, ++ void *p, void *start) ++{ ++ efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID; ++ struct efi_initrd *initrd_table = p; ++ ++ /* efi_configuration_table 2 */ ++ guidcpy(&systab->tables[1].guid, &tbl_guid); ++ systab->tables[1].table = (struct efi_configuration_table *)(p - start); ++ systab->nr_tables = 2; ++ ++ initrd_table->base = initrd_offset; ++ initrd_table->size = initrd_size; ++} ++ ++static void init_efi_fdt_table(struct efi_system_table *systab) ++{ ++ efi_guid_t tbl_guid = DEVICE_TREE_GUID; ++ ++ /* efi_configuration_table 3 */ ++ guidcpy(&systab->tables[2].guid, &tbl_guid); ++ systab->tables[2].table = (void *)FDT_BASE; ++ systab->nr_tables = 3; ++} ++ ++static void init_systab(struct loongarch_boot_info *info, void *p, void *start) ++{ ++ void *bp_tables_start; ++ struct efi_system_table *systab = p; ++ ++ info->a2 = p - start; ++ ++ systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; ++ systab->hdr.revision = EFI_SPECIFICATION_VERSION; ++ systab->hdr.revision = sizeof(struct efi_system_table), ++ systab->fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8; ++ systab->runtime = 0; ++ systab->boottime = 0; ++ systab->nr_tables = 0; ++ ++ p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB); ++ ++ systab->tables = p; ++ bp_tables_start = p; ++ ++ init_efi_boot_memmap(systab, p, start); ++ p += ROUND_UP(sizeof(struct efi_boot_memmap) + ++ sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB); ++ init_efi_initrd_table(systab, p, start); ++ p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB); ++ init_efi_fdt_table(systab); ++ ++ systab->tables = (struct efi_configuration_table *)(bp_tables_start - start); ++} ++ ++static void init_cmdline(struct loongarch_boot_info *info, void *p, void *start) ++{ ++ hwaddr cmdline_addr = p - start; ++ ++ info->a0 = 1; ++ info->a1 = cmdline_addr; ++ ++ g_strlcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE); ++} ++ ++static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) ++{ ++ return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS); ++} ++ ++static int64_t load_kernel_info(struct loongarch_boot_info *info) ++{ ++ uint64_t kernel_entry, kernel_low, kernel_high; ++ ssize_t kernel_size; ++ ++ kernel_size = load_elf(info->kernel_filename, NULL, ++ cpu_loongarch_virt_to_phys, NULL, ++ &kernel_entry, &kernel_low, ++ &kernel_high, NULL, 0, ++ EM_LOONGARCH, 1, 0); ++ ++ if (kernel_size < 0) { ++ error_report("could not load kernel '%s': %s", ++ info->kernel_filename, ++ load_elf_strerror(kernel_size)); ++ exit(1); ++ } ++ ++ if (info->initrd_filename) { ++ initrd_size = get_image_size(info->initrd_filename); ++ if (initrd_size > 0) { ++ initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB); ++ ++ if (initrd_offset + initrd_size > info->ram_size) { ++ error_report("memory too small for initial ram disk '%s'", ++ info->initrd_filename); ++ exit(1); ++ } ++ ++ initrd_size = load_image_targphys(info->initrd_filename, initrd_offset, ++ info->ram_size - initrd_offset); ++ } ++ ++ if (initrd_size == (target_ulong)-1) { ++ error_report("could not load initial ram disk '%s'", ++ info->initrd_filename); ++ exit(1); ++ } ++ } else { ++ initrd_size = 0; ++ } ++ ++ return kernel_entry; ++} ++ ++static void reset_load_elf(void *opaque) ++{ ++ LoongArchCPU *cpu = opaque; ++ CPULoongArchState *env = &cpu->env; ++ ++ cpu_reset(CPU(cpu)); ++ if (env->load_elf) { ++ if (cpu == LOONGARCH_CPU(first_cpu)) { ++ env->gpr[4] = env->boot_info->a0; ++ env->gpr[5] = env->boot_info->a1; ++ env->gpr[6] = env->boot_info->a2; ++ } ++ cpu_set_pc(CPU(cpu), env->elf_address); ++ } ++} ++ ++static void fw_cfg_add_kernel_info(struct loongarch_boot_info *info, ++ FWCfgState *fw_cfg) ++{ ++ /* ++ * Expose the kernel, the command line, and the initrd in fw_cfg. ++ * We don't process them here at all, it's all left to the ++ * firmware. ++ */ ++ load_image_to_fw_cfg(fw_cfg, ++ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA, ++ info->kernel_filename, ++ false); ++ ++ if (info->initrd_filename) { ++ load_image_to_fw_cfg(fw_cfg, ++ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA, ++ info->initrd_filename, false); ++ } ++ ++ if (info->kernel_cmdline) { ++ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, ++ strlen(info->kernel_cmdline) + 1); ++ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, ++ info->kernel_cmdline); ++ } ++} ++ ++static void loongarch_firmware_boot(LoongArchVirtMachineState *lvms, ++ struct loongarch_boot_info *info) ++{ ++ fw_cfg_add_kernel_info(info, lvms->fw_cfg); ++} ++ ++static void init_boot_rom(struct loongarch_boot_info *info, void *p) ++{ ++ void *start = p; ++ ++ init_cmdline(info, p, start); ++ p += COMMAND_LINE_SIZE; ++ ++ init_systab(info, p, start); ++} ++ ++static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) ++{ ++ void *p, *bp; ++ int64_t kernel_addr = 0; ++ LoongArchCPU *lacpu; ++ CPUState *cs; ++ ++ if (info->kernel_filename) { ++ kernel_addr = load_kernel_info(info); ++ } else { ++ if(!qtest_enabled()) { ++ error_report("Need kernel filename\n"); ++ exit(1); ++ } ++ } ++ ++ /* Load cmdline and system tables at [0 - 1 MiB] */ ++ p = g_malloc0(1 * MiB); ++ bp = p; ++ init_boot_rom(info, p); ++ rom_add_blob_fixed_as("boot_info", bp, 1 * MiB, 0, &address_space_memory); ++ ++ /* Load slave boot code at pflash0 . */ ++ void *boot_code = g_malloc0(VIRT_FLASH0_SIZE); ++ memcpy(boot_code, &slave_boot_code, sizeof(slave_boot_code)); ++ rom_add_blob_fixed("boot_code", boot_code, VIRT_FLASH0_SIZE, VIRT_FLASH0_BASE); ++ ++ CPU_FOREACH(cs) { ++ lacpu = LOONGARCH_CPU(cs); ++ lacpu->env.load_elf = true; ++ if (cs == first_cpu) { ++ lacpu->env.elf_address = kernel_addr; ++ } else { ++ lacpu->env.elf_address = VIRT_FLASH0_BASE; ++ } ++ lacpu->env.boot_info = info; ++ } ++ ++ g_free(boot_code); ++ g_free(bp); ++} ++ ++void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info) ++{ ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(ms); ++ int i; ++ ++ /* register reset function */ ++ for (i = 0; i < ms->smp.cpus; i++) { ++ qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(i))); ++ } ++ ++ info->kernel_filename = ms->kernel_filename; ++ info->kernel_cmdline = ms->kernel_cmdline; ++ info->initrd_filename = ms->initrd_filename; ++ ++ if (lvms->bios_loaded) { ++ loongarch_firmware_boot(lvms, info); ++ } else { ++ loongarch_direct_kernel_boot(info); ++ } ++} +diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c +index f15a174..35aeb2d 100644 +--- a/hw/loongarch/fw_cfg.c ++++ b/hw/loongarch/fw_cfg.c +@@ -17,7 +17,7 @@ static void fw_cfg_boot_set(void *opaque, const char *boot_device, + fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); + } + +-FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms) ++FWCfgState *virt_fw_cfg_init(ram_addr_t ram_size, MachineState *ms) + { + FWCfgState *fw_cfg; + int max_cpus = ms->smp.max_cpus; +diff --git a/hw/loongarch/fw_cfg.h b/hw/loongarch/fw_cfg.h +index 7c0de4d..27ee682 100644 +--- a/hw/loongarch/fw_cfg.h ++++ b/hw/loongarch/fw_cfg.h +@@ -11,5 +11,5 @@ + #include "hw/boards.h" + #include "hw/nvram/fw_cfg.h" + +-FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms); ++FWCfgState *virt_fw_cfg_init(ram_addr_t ram_size, MachineState *ms); + #endif +diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build +index c042150..d306d82 100644 +--- a/hw/loongarch/meson.build ++++ b/hw/loongarch/meson.build +@@ -1,6 +1,7 @@ + loongarch_ss = ss.source_set() + loongarch_ss.add(files( + 'fw_cfg.c', ++ 'boot.c', + )) + loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: [files('virt.c'), fdt]) + loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c')) +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 01e59f3..4e77901 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -10,13 +10,13 @@ + #include "qapi/error.h" + #include "hw/boards.h" + #include "hw/char/serial.h" ++#include "sysemu/kvm.h" ++#include "sysemu/tcg.h" + #include "sysemu/sysemu.h" + #include "sysemu/qtest.h" + #include "sysemu/runstate.h" + #include "sysemu/reset.h" + #include "sysemu/rtc.h" +-#include "sysemu/tcg.h" +-#include "sysemu/kvm.h" + #include "hw/loongarch/virt.h" + #include "exec/address-spaces.h" + #include "hw/irq.h" +@@ -46,42 +46,36 @@ + #include "sysemu/tpm.h" + #include "sysemu/block-backend.h" + #include "hw/block/flash.h" ++#include "hw/virtio/virtio-iommu.h" + #include "qemu/error-report.h" ++#include "qemu/guest-random.h" + +- +-struct loaderparams { +- uint64_t ram_size; +- const char *kernel_filename; +- const char *kernel_cmdline; +- const char *initrd_filename; +-}; +- +-static bool virt_is_veiointc_enabled(LoongArchMachineState *lams) ++static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms) + { +- if (lams->veiointc == ON_OFF_AUTO_OFF) { ++ if (lvms->veiointc == ON_OFF_AUTO_OFF) { + return false; + } + return true; + } + + static void virt_get_veiointc(Object *obj, Visitor *v, const char *name, +- void *opaque, Error **errp) ++ void *opaque, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); +- OnOffAuto veiointc = lams->veiointc; ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); ++ OnOffAuto veiointc = lvms->veiointc; + + visit_type_OnOffAuto(v, name, &veiointc, errp); + } + + static void virt_set_veiointc(Object *obj, Visitor *v, const char *name, +- void *opaque, Error **errp) ++ void *opaque, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + +- visit_type_OnOffAuto(v, name, &lams->veiointc, errp); ++ visit_type_OnOffAuto(v, name, &lvms->veiointc, errp); + } + +-static PFlashCFI01 *virt_flash_create1(LoongArchMachineState *lams, ++static PFlashCFI01 *virt_flash_create1(LoongArchVirtMachineState *lvms, + const char *name, + const char *alias_prop_name) + { +@@ -96,16 +90,16 @@ static PFlashCFI01 *virt_flash_create1(LoongArchMachineState *lams, + qdev_prop_set_uint16(dev, "id2", 0x00); + qdev_prop_set_uint16(dev, "id3", 0x00); + qdev_prop_set_string(dev, "name", name); +- object_property_add_child(OBJECT(lams), name, OBJECT(dev)); +- object_property_add_alias(OBJECT(lams), alias_prop_name, ++ object_property_add_child(OBJECT(lvms), name, OBJECT(dev)); ++ object_property_add_alias(OBJECT(lvms), alias_prop_name, + OBJECT(dev), "drive"); + return PFLASH_CFI01(dev); + } + +-static void virt_flash_create(LoongArchMachineState *lams) ++static void virt_flash_create(LoongArchVirtMachineState *lvms) + { +- lams->flash[0] = virt_flash_create1(lams, "virt.flash0", "pflash0"); +- lams->flash[1] = virt_flash_create1(lams, "virt.flash1", "pflash1"); ++ lvms->flash[0] = virt_flash_create1(lvms, "virt.flash0", "pflash0"); ++ lvms->flash[1] = virt_flash_create1(lvms, "virt.flash1", "pflash1"); + } + + static void virt_flash_map1(PFlashCFI01 *flash, +@@ -131,19 +125,114 @@ static void virt_flash_map1(PFlashCFI01 *flash, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); + } + +-static void virt_flash_map(LoongArchMachineState *lams, ++static void virt_flash_map(LoongArchVirtMachineState *lvms, + MemoryRegion *sysmem) + { +- PFlashCFI01 *flash0 = lams->flash[0]; +- PFlashCFI01 *flash1 = lams->flash[1]; ++ PFlashCFI01 *flash0 = lvms->flash[0]; ++ PFlashCFI01 *flash1 = lvms->flash[1]; + + virt_flash_map1(flash0, VIRT_FLASH0_BASE, VIRT_FLASH0_SIZE, sysmem); + virt_flash_map1(flash1, VIRT_FLASH1_BASE, VIRT_FLASH1_SIZE, sysmem); + } + +-static void fdt_add_flash_node(LoongArchMachineState *lams) ++static void fdt_add_cpuic_node(LoongArchVirtMachineState *lvms, ++ uint32_t *cpuintc_phandle) ++{ ++ MachineState *ms = MACHINE(lvms); ++ char *nodename; ++ ++ *cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt); ++ nodename = g_strdup_printf("/cpuic"); ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", ++ "loongson,cpu-interrupt-controller"); ++ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1); ++ g_free(nodename); ++} ++ ++static void fdt_add_eiointc_node(LoongArchVirtMachineState *lvms, ++ uint32_t *cpuintc_phandle, ++ uint32_t *eiointc_phandle) ++{ ++ MachineState *ms = MACHINE(lvms); ++ char *nodename; ++ hwaddr extioi_base = APIC_BASE; ++ hwaddr extioi_size = EXTIOI_SIZE; ++ ++ *eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt); ++ nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base); ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", ++ "loongson,ls2k2000-eiointc"); ++ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", ++ *cpuintc_phandle); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, ++ extioi_base, 0x0, extioi_size); ++ g_free(nodename); ++} ++ ++static void fdt_add_pch_pic_node(LoongArchVirtMachineState *lvms, ++ uint32_t *eiointc_phandle, ++ uint32_t *pch_pic_phandle) ++{ ++ MachineState *ms = MACHINE(lvms); ++ char *nodename; ++ hwaddr pch_pic_base = VIRT_PCH_REG_BASE; ++ hwaddr pch_pic_size = VIRT_PCH_REG_SIZE; ++ ++ *pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt); ++ nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base); ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_pic_phandle); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", ++ "loongson,pch-pic-1.0"); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, ++ pch_pic_base, 0, pch_pic_size); ++ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", ++ *eiointc_phandle); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0); ++ g_free(nodename); ++} ++ ++static void fdt_add_pch_msi_node(LoongArchVirtMachineState *lvms, ++ uint32_t *eiointc_phandle, ++ uint32_t *pch_msi_phandle) ++{ ++ MachineState *ms = MACHINE(lvms); ++ char *nodename; ++ hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW; ++ hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE; ++ ++ *pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt); ++ nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base); ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", ++ "loongson,pch-msi-1.0"); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", ++ 0, pch_msi_base, ++ 0, pch_msi_size); ++ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", ++ *eiointc_phandle); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec", ++ VIRT_PCH_PIC_IRQ_NUM); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs", ++ EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM); ++ g_free(nodename); ++} ++ ++static void fdt_add_flash_node(LoongArchVirtMachineState *lvms) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + char *nodename; + MemoryRegion *flash_mem; + +@@ -153,11 +242,11 @@ static void fdt_add_flash_node(LoongArchMachineState *lams) + hwaddr flash1_base; + hwaddr flash1_size; + +- flash_mem = pflash_cfi01_get_memory(lams->flash[0]); ++ flash_mem = pflash_cfi01_get_memory(lvms->flash[0]); + flash0_base = flash_mem->addr; + flash0_size = memory_region_size(flash_mem); + +- flash_mem = pflash_cfi01_get_memory(lams->flash[1]); ++ flash_mem = pflash_cfi01_get_memory(lvms->flash[1]); + flash1_base = flash_mem->addr; + flash1_size = memory_region_size(flash_mem); + +@@ -171,41 +260,53 @@ static void fdt_add_flash_node(LoongArchMachineState *lams) + g_free(nodename); + } + +-static void fdt_add_rtc_node(LoongArchMachineState *lams) ++static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms, ++ uint32_t *pch_pic_phandle) + { + char *nodename; + hwaddr base = VIRT_RTC_REG_BASE; + hwaddr size = VIRT_RTC_LEN; +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + + nodename = g_strdup_printf("/rtc@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); +- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "loongson,ls7a-rtc"); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", ++ "loongson,ls7a-rtc"); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", ++ VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", ++ *pch_pic_phandle); + g_free(nodename); + } + +-static void fdt_add_uart_node(LoongArchMachineState *lams) ++static void fdt_add_uart_node(LoongArchVirtMachineState *lvms, ++ uint32_t *pch_pic_phandle, hwaddr base, ++ int irq, bool chosen) + { + char *nodename; +- hwaddr base = VIRT_UART_BASE; + hwaddr size = VIRT_UART_SIZE; +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + + nodename = g_strdup_printf("/serial@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a"); + qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size); + qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000); +- qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); ++ if (chosen) ++ qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0x4); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", ++ *pch_pic_phandle); + g_free(nodename); + } + +-static void create_fdt(LoongArchMachineState *lams) ++static void create_fdt(LoongArchVirtMachineState *lvms) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); ++ uint8_t rng_seed[32]; + +- ms->fdt = create_device_tree(&lams->fdt_size); ++ ms->fdt = create_device_tree(&lvms->fdt_size); + if (!ms->fdt) { + error_report("create_device_tree() failed"); + exit(1); +@@ -217,12 +318,16 @@ static void create_fdt(LoongArchMachineState *lams) + qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); + qemu_fdt_add_subnode(ms->fdt, "/chosen"); ++ ++ /* Pass seed to RNG */ ++ qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); ++ qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + } + +-static void fdt_add_cpu_nodes(const LoongArchMachineState *lams) ++static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms) + { + int num; +- const MachineState *ms = MACHINE(lams); ++ const MachineState *ms = MACHINE(lvms); + int smp_cpus = ms->smp.cpus; + + qemu_fdt_add_subnode(ms->fdt, "/cpus"); +@@ -276,11 +381,11 @@ static void fdt_add_cpu_nodes(const LoongArchMachineState *lams) + } + } + +-static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams) ++static void fdt_add_fw_cfg_node(const LoongArchVirtMachineState *lvms) + { + char *nodename; + hwaddr base = VIRT_FWCFG_BASE; +- const MachineState *ms = MACHINE(lams); ++ const MachineState *ms = MACHINE(lvms); + + nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); +@@ -292,7 +397,62 @@ static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams) + g_free(nodename); + } + +-static void fdt_add_pcie_node(const LoongArchMachineState *lams) ++static void fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState *lvms, ++ char *nodename, ++ uint32_t *pch_pic_phandle) ++{ ++ int pin, dev; ++ uint32_t irq_map_stride = 0; ++ uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {}; ++ uint32_t *irq_map = full_irq_map; ++ const MachineState *ms = MACHINE(lvms); ++ ++ /* This code creates a standard swizzle of interrupts such that ++ * each device's first interrupt is based on it's PCI_SLOT number. ++ * (See pci_swizzle_map_irq_fn()) ++ * ++ * We only need one entry per interrupt in the table (not one per ++ * possible slot) seeing the interrupt-map-mask will allow the table ++ * to wrap to any number of devices. ++ */ ++ ++ for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { ++ int devfn = dev * 0x8; ++ ++ for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { ++ int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); ++ int i = 0; ++ ++ /* Fill PCI address cells */ ++ irq_map[i] = cpu_to_be32(devfn << 8); ++ i += 3; ++ ++ /* Fill PCI Interrupt cells */ ++ irq_map[i] = cpu_to_be32(pin + 1); ++ i += 1; ++ ++ /* Fill interrupt controller phandle and cells */ ++ irq_map[i++] = cpu_to_be32(*pch_pic_phandle); ++ irq_map[i++] = cpu_to_be32(irq_nr); ++ ++ if (!irq_map_stride) { ++ irq_map_stride = i; ++ } ++ irq_map += irq_map_stride; ++ } ++ } ++ ++ ++ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map, ++ GPEX_NUM_IRQS * GPEX_NUM_IRQS * ++ irq_map_stride * sizeof(uint32_t)); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask", ++ 0x1800, 0, 0, 0x7); ++} ++ ++static void fdt_add_pcie_node(const LoongArchVirtMachineState *lvms, ++ uint32_t *pch_pic_phandle, ++ uint32_t *pch_msi_phandle) + { + char *nodename; + hwaddr base_mmio = VIRT_PCI_MEM_BASE; +@@ -303,7 +463,7 @@ static void fdt_add_pcie_node(const LoongArchMachineState *lams) + hwaddr size_pcie = VIRT_PCI_CFG_SIZE; + hwaddr base = base_pcie; + +- const MachineState *ms = MACHINE(lams); ++ const MachineState *ms = MACHINE(lvms); + + nodename = g_strdup_printf("/pcie@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); +@@ -323,34 +483,11 @@ static void fdt_add_pcie_node(const LoongArchMachineState *lams) + 2, base_pio, 2, size_pio, + 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, + 2, base_mmio, 2, size_mmio); +- g_free(nodename); +-} ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map", ++ 0, *pch_msi_phandle, 0, 0x10000); + +-static void fdt_add_irqchip_node(LoongArchMachineState *lams) +-{ +- MachineState *ms = MACHINE(lams); +- char *nodename; +- uint32_t irqchip_phandle; ++ fdt_add_pcie_irq_map_node(lvms, nodename, pch_pic_phandle); + +- irqchip_phandle = qemu_fdt_alloc_phandle(ms->fdt); +- qemu_fdt_setprop_cell(ms->fdt, "/", "interrupt-parent", irqchip_phandle); +- +- nodename = g_strdup_printf("/intc@%lx", VIRT_IOAPIC_REG_BASE); +- qemu_fdt_add_subnode(ms->fdt, nodename); +- qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 3); +- qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); +- qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2); +- qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 0x2); +- qemu_fdt_setprop(ms->fdt, nodename, "ranges", NULL, 0); +- +- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", +- "loongarch,ls7a"); +- +- qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", +- 2, VIRT_IOAPIC_REG_BASE, +- 2, PCH_PIC_ROUTE_ENTRY_OFFSET); +- +- qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", irqchip_phandle); + g_free(nodename); + } + +@@ -360,7 +497,8 @@ static void fdt_add_memory_node(MachineState *ms, + char *nodename = g_strdup_printf("/memory@%" PRIx64, base); + + qemu_fdt_add_subnode(ms->fdt, nodename); +- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 2, base, 2, size); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", base >> 32, base, ++ size >> 32, size); + qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory"); + + if (ms->numa_state && ms->numa_state->num_nodes) { +@@ -370,58 +508,89 @@ static void fdt_add_memory_node(MachineState *ms, + g_free(nodename); + } + +-static void virt_build_smbios(LoongArchMachineState *lams) ++static void fdt_add_memory_nodes(MachineState *ms) + { +- MachineState *ms = MACHINE(lams); +- MachineClass *mc = MACHINE_GET_CLASS(lams); ++ hwaddr base, size, ram_size, gap; ++ int i, nb_numa_nodes, nodes; ++ NodeInfo *numa_info; ++ ++ ram_size = ms->ram_size; ++ base = VIRT_LOWMEM_BASE; ++ gap = VIRT_LOWMEM_SIZE; ++ nodes = nb_numa_nodes = ms->numa_state->num_nodes; ++ numa_info = ms->numa_state->nodes; ++ if (!nodes) { ++ nodes = 1; ++ } ++ ++ for (i = 0; i < nodes; i++) { ++ if (nb_numa_nodes) { ++ size = numa_info[i].node_mem; ++ } else { ++ size = ram_size; ++ } ++ ++ /* ++ * memory for the node splited into two part ++ * lowram: [base, +gap) ++ * highram: [VIRT_HIGHMEM_BASE, +(len - gap)) ++ */ ++ if (size >= gap) { ++ fdt_add_memory_node(ms, base, gap, i); ++ size -= gap; ++ base = VIRT_HIGHMEM_BASE; ++ gap = ram_size - VIRT_LOWMEM_SIZE; ++ } ++ ++ if (size) { ++ fdt_add_memory_node(ms, base, size, i); ++ base += size; ++ gap -= size; ++ } ++ } ++} ++ ++static void virt_build_smbios(LoongArchVirtMachineState *lvms) ++{ ++ MachineState *ms = MACHINE(lvms); ++ MachineClass *mc = MACHINE_GET_CLASS(lvms); + uint8_t *smbios_tables, *smbios_anchor; + size_t smbios_tables_len, smbios_anchor_len; + const char *product = "QEMU Virtual Machine"; + +- if (!lams->fw_cfg) { ++ if (!lvms->fw_cfg) { + return; + } + + smbios_set_defaults("QEMU", product, mc->name, false, + true, SMBIOS_ENTRY_POINT_TYPE_64); +- + smbios_get_tables(ms, NULL, 0, &smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len, &error_fatal); + + if (smbios_anchor) { +- fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-tables", ++ fw_cfg_add_file(lvms->fw_cfg, "etc/smbios/smbios-tables", + smbios_tables, smbios_tables_len); +- fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-anchor", ++ fw_cfg_add_file(lvms->fw_cfg, "etc/smbios/smbios-anchor", + smbios_anchor, smbios_anchor_len); + } + } + +-static void virt_machine_done(Notifier *notifier, void *data) ++static void virt_done(Notifier *notifier, void *data) + { +- LoongArchMachineState *lams = container_of(notifier, +- LoongArchMachineState, machine_done); +- virt_build_smbios(lams); +- loongarch_acpi_setup(lams); ++ LoongArchVirtMachineState *lvms = container_of(notifier, ++ LoongArchVirtMachineState, machine_done); ++ virt_build_smbios(lvms); ++ loongarch_acpi_setup(lvms); + } + + static void virt_powerdown_req(Notifier *notifier, void *opaque) + { +- LoongArchMachineState *s = container_of(notifier, +- LoongArchMachineState, powerdown_notifier); ++ LoongArchVirtMachineState *s; + ++ s = container_of(notifier, LoongArchVirtMachineState, powerdown_notifier); + acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS); + } + +-struct memmap_entry { +- uint64_t address; +- uint64_t length; +- uint32_t type; +- uint32_t reserved; +-}; +- +-static struct memmap_entry *memmap_table; +-static unsigned memmap_entries; +- + static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) + { + /* Ensure there are no duplicate entries. */ +@@ -438,35 +607,11 @@ static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) + memmap_entries++; + } + +-static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) +-{ +- return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS); +-} +- +-static int64_t load_kernel_info(const struct loaderparams *loaderparams) +-{ +- uint64_t kernel_entry, kernel_low, kernel_high; +- ssize_t kernel_size; +- +- kernel_size = load_elf(loaderparams->kernel_filename, NULL, +- cpu_loongarch_virt_to_phys, NULL, +- &kernel_entry, &kernel_low, +- &kernel_high, NULL, 0, +- EM_LOONGARCH, 1, 0); +- +- if (kernel_size < 0) { +- error_report("could not load kernel '%s': %s", +- loaderparams->kernel_filename, +- load_elf_strerror(kernel_size)); +- exit(1); +- } +- return kernel_entry; +-} +- +-static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState *lams) ++static DeviceState *create_acpi_ged(DeviceState *pch_pic, ++ LoongArchVirtMachineState *lvms) + { + DeviceState *dev; +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + uint32_t event = ACPI_GED_PWR_DOWN_EVT; + + if (ms->ram_slots) { +@@ -513,9 +658,12 @@ static DeviceState *create_platform_bus(DeviceState *pch_pic) + return dev; + } + +-static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState *lams) ++static void virt_devices_init(DeviceState *pch_pic, ++ LoongArchVirtMachineState *lvms, ++ uint32_t *pch_pic_phandle, ++ uint32_t *pch_msi_phandle) + { +- MachineClass *mc = MACHINE_GET_CLASS(lams); ++ MachineClass *mc = MACHINE_GET_CLASS(lvms); + DeviceState *gpex_dev; + SysBusDevice *d; + PCIBus *pci_bus; +@@ -527,7 +675,7 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState * + d = SYS_BUS_DEVICE(gpex_dev); + sysbus_realize_and_unref(d, &error_fatal); + pci_bus = PCI_HOST_BRIDGE(gpex_dev)->bus; +- lams->pci_bus = pci_bus; ++ lvms->pci_bus = pci_bus; + + /* Map only part size_ecam bytes of ECAM space */ + ecam_alias = g_new0(MemoryRegion, 1); +@@ -559,13 +707,23 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState * + gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i); + } + +- serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0, +- qdev_get_gpio_in(pch_pic, +- VIRT_UART_IRQ - VIRT_GSI_BASE), +- 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); +- fdt_add_uart_node(lams); ++ /* Add pcie node */ ++ fdt_add_pcie_node(lvms, pch_pic_phandle, pch_msi_phandle); + +- /* Network init */ ++ /* ++ * Create uart fdt node in reverse order so that they appear ++ * in the finished device tree lowest address first ++ */ ++ for (i = VIRT_UART_COUNT; i --> 0;) { ++ hwaddr base = VIRT_UART_BASE + i * VIRT_UART_SIZE; ++ int irq = VIRT_UART_IRQ + i - VIRT_GSI_BASE; ++ serial_mm_init(get_system_memory(), base, 0, ++ qdev_get_gpio_in(pch_pic, irq), ++ 115200, serial_hd(i), DEVICE_LITTLE_ENDIAN); ++ fdt_add_uart_node(lvms, pch_pic_phandle, base, irq, i == 0); ++ } ++ ++ /* Network init */ + for (i = 0; i < nb_nics; i++) { + pci_nic_init_nofail(&nd_table[i], pci_bus, mc->default_nic, NULL); + } +@@ -578,17 +736,17 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState * + sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE, + qdev_get_gpio_in(pch_pic, + VIRT_RTC_IRQ - VIRT_GSI_BASE)); +- fdt_add_rtc_node(lams); ++ fdt_add_rtc_node(lvms, pch_pic_phandle); + + /* acpi ged */ +- lams->acpi_ged = create_acpi_ged(pch_pic, lams); ++ lvms->acpi_ged = create_acpi_ged(pch_pic, lvms); + /* platform bus */ +- lams->platform_bus_dev = create_platform_bus(pch_pic); ++ lvms->platform_bus_dev = create_platform_bus(pch_pic); + } + +-static void loongarch_irq_init(LoongArchMachineState *lams) ++static void virt_irq_init(LoongArchVirtMachineState *lvms) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + DeviceState *pch_pic, *pch_msi, *cpudev; + DeviceState *ipi, *extioi; + SysBusDevice *d; +@@ -596,27 +754,50 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + CPULoongArchState *env; + CPUState *cpu_state; + int cpu, pin, i, start, num; ++ uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, pch_msi_phandle; + + /* +- * The connection of interrupts: +- * +-----+ +---------+ +-------+ +- * | IPI |--> | CPUINTC | <-- | Timer | +- * +-----+ +---------+ +-------+ +- * ^ +- * | +- * +---------+ +- * | EIOINTC | +- * +---------+ +- * ^ ^ +- * | | +- * +---------+ +---------+ +- * | PCH-PIC | | PCH-MSI | +- * +---------+ +---------+ +- * ^ ^ ^ +- * | | | +- * +--------+ +---------+ +---------+ +- * | UARTs | | Devices | | Devices | +- * +--------+ +---------+ +---------+ ++ * Extended IRQ model. ++ * | ++ * +-----------+ +-------------|--------+ +-----------+ ++ * | IPI/Timer | --> | CPUINTC(0-3)|(4-255) | <-- | IPI/Timer | ++ * +-----------+ +-------------|--------+ +-----------+ ++ * ^ | ++ * | ++ * +---------+ ++ * | EIOINTC | ++ * +---------+ ++ * ^ ^ ++ * | | ++ * +---------+ +---------+ ++ * | PCH-PIC | | PCH-MSI | ++ * +---------+ +---------+ ++ * ^ ^ ^ ++ * | | | ++ * +--------+ +---------+ +---------+ ++ * | UARTs | | Devices | | Devices | ++ * +--------+ +---------+ +---------+ ++ * ++ * Virt extended IRQ model. ++ * ++ * +-----+ +---------------+ +-------+ ++ * | IPI |--> | CPUINTC(0-255)| <-- | Timer | ++ * +-----+ +---------------+ +-------+ ++ * ^ ++ * | ++ * +-----------+ ++ * | V-EIOINTC | ++ * +-----------+ ++ * ^ ^ ++ * | | ++ * +---------+ +---------+ ++ * | PCH-PIC | | PCH-MSI | ++ * +---------+ +---------+ ++ * ^ ^ ^ ++ * | | | ++ * +--------+ +---------+ +---------+ ++ * | UARTs | | Devices | | Devices | ++ * +--------+ +---------+ +---------+ + */ + + /* Create IPI device */ +@@ -625,17 +806,20 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); + + /* IPI iocsr memory region */ +- memory_region_add_subregion(&lams->system_iocsr, SMP_IPI_MAILBOX, ++ memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX, + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0)); +- memory_region_add_subregion(&lams->system_iocsr, MAIL_SEND_ADDR, ++ memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR, + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1)); + ++ /* Add cpu interrupt-controller */ ++ fdt_add_cpuic_node(lvms, &cpuintc_phandle); ++ + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { + cpu_state = qemu_get_cpu(cpu); + cpudev = DEVICE(cpu_state); + lacpu = LOONGARCH_CPU(cpu_state); + env = &(lacpu->env); +- env->address_space_iocsr = &lams->as_iocsr; ++ env->address_space_iocsr = &lvms->as_iocsr; + + /* connect ipi irq to cpu irq */ + qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); +@@ -645,18 +829,16 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + /* Create EXTIOI device */ + extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); + qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus); +- if (virt_is_veiointc_enabled(lams)) { ++ if (virt_is_veiointc_enabled(lvms)) { + qdev_prop_set_bit(extioi, "has-virtualization-extension", true); + } + sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); +- +- memory_region_add_subregion(&lams->system_iocsr, APIC_BASE, +- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0)); +- if (virt_is_veiointc_enabled(lams)) { +- memory_region_add_subregion(&lams->system_iocsr, EXTIOI_VIRT_BASE, +- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1)); ++ memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0)); ++ if (virt_is_veiointc_enabled(lvms)) { ++ memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1)); + } +- lams->extioi = extioi; + + /* + * connect ext irq to the cpu irq +@@ -670,6 +852,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + } + } + ++ /* Add Extend I/O Interrupt Controller node */ ++ fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle); ++ + pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); + num = VIRT_PCH_PIC_IRQ_NUM; + qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num); +@@ -689,6 +874,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); + } + ++ /* Add PCH PIC node */ ++ fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle); ++ + pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); + start = num; + num = EXTIOI_IRQS - start; +@@ -703,28 +891,31 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + qdev_get_gpio_in(extioi, i + start)); + } + +- loongarch_devices_init(pch_pic, lams); ++ /* Add PCH MSI node */ ++ fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle); ++ ++ virt_devices_init(pch_pic, lvms, &pch_pic_phandle, &pch_msi_phandle); + } + +-static void loongarch_firmware_init(LoongArchMachineState *lams) ++static void virt_firmware_init(LoongArchVirtMachineState *lvms) + { +- char *filename = MACHINE(lams)->firmware; ++ char *filename = MACHINE(lvms)->firmware; + char *bios_name = NULL; + int bios_size, i; + BlockBackend *pflash_blk0; + MemoryRegion *mr; + +- lams->bios_loaded = false; ++ lvms->bios_loaded = false; + + /* Map legacy -drive if=pflash to machine properties */ +- for (i = 0; i < ARRAY_SIZE(lams->flash); i++) { +- pflash_cfi01_legacy_drive(lams->flash[i], ++ for (i = 0; i < ARRAY_SIZE(lvms->flash); i++) { ++ pflash_cfi01_legacy_drive(lvms->flash[i], + drive_get(IF_PFLASH, 0, i)); + } + +- virt_flash_map(lams, get_system_memory()); ++ virt_flash_map(lvms, get_system_memory()); + +- pflash_blk0 = pflash_cfi01_get_blk(lams->flash[0]); ++ pflash_blk0 = pflash_cfi01_get_blk(lvms->flash[0]); + + if (pflash_blk0) { + if (filename) { +@@ -732,7 +923,7 @@ static void loongarch_firmware_init(LoongArchMachineState *lams) + "options at once"); + exit(1); + } +- lams->bios_loaded = true; ++ lvms->bios_loaded = true; + return; + } + +@@ -743,92 +934,31 @@ static void loongarch_firmware_init(LoongArchMachineState *lams) + exit(1); + } + +- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(lams->flash[0]), 0); ++ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(lvms->flash[0]), 0); + bios_size = load_image_mr(bios_name, mr); + if (bios_size < 0) { + error_report("Could not load ROM image '%s'", bios_name); + exit(1); + } + g_free(bios_name); +- lams->bios_loaded = true; ++ lvms->bios_loaded = true; + } + } + +-static void reset_load_elf(void *opaque) ++static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr, ++ uint64_t val, unsigned size, ++ MemTxAttrs attrs) + { +- LoongArchCPU *cpu = opaque; +- CPULoongArchState *env = &cpu->env; +- +- cpu_reset(CPU(cpu)); +- if (env->load_elf) { +- cpu_set_pc(CPU(cpu), env->elf_address); +- } +-} +- +-static void fw_cfg_add_kernel_info(const struct loaderparams *loaderparams, +- FWCfgState *fw_cfg) +-{ +- /* +- * Expose the kernel, the command line, and the initrd in fw_cfg. +- * We don't process them here at all, it's all left to the +- * firmware. +- */ +- load_image_to_fw_cfg(fw_cfg, +- FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA, +- loaderparams->kernel_filename, +- false); +- +- if (loaderparams->initrd_filename) { +- load_image_to_fw_cfg(fw_cfg, +- FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA, +- loaderparams->initrd_filename, false); +- } +- +- if (loaderparams->kernel_cmdline) { +- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, +- strlen(loaderparams->kernel_cmdline) + 1); +- fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, +- loaderparams->kernel_cmdline); +- } +-} +- +-static void loongarch_firmware_boot(LoongArchMachineState *lams, +- const struct loaderparams *loaderparams) +-{ +- fw_cfg_add_kernel_info(loaderparams, lams->fw_cfg); +-} +- +-static void loongarch_direct_kernel_boot(LoongArchMachineState *lams, +- const struct loaderparams *loaderparams) +-{ +- MachineState *machine = MACHINE(lams); +- int64_t kernel_addr = 0; +- LoongArchCPU *lacpu; +- int i; +- +- kernel_addr = load_kernel_info(loaderparams); +- if (!machine->firmware) { +- for (i = 0; i < machine->smp.cpus; i++) { +- lacpu = LOONGARCH_CPU(qemu_get_cpu(i)); +- lacpu->env.load_elf = true; +- lacpu->env.elf_address = kernel_addr; +- } +- } +-} +- +-static MemTxResult loongarch_qemu_write(void *opaque, hwaddr addr, uint64_t val, +- unsigned size, MemTxAttrs attrs) +-{ +- LoongArchMachineState *lams = LOONGARCH_MACHINE(opaque); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque); + uint64_t features; + + switch (addr) { + case MISC_FUNC_REG: +- if (!virt_is_veiointc_enabled(lams)) { ++ if (!virt_is_veiointc_enabled(lvms)) { + return MEMTX_OK; + } + +- features = address_space_ldl(&lams->as_iocsr, ++ features = address_space_ldl(&lvms->as_iocsr, + EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG, + attrs, NULL); + if (val & BIT_ULL(IOCSRM_EXTIOI_EN)) { +@@ -838,19 +968,22 @@ static MemTxResult loongarch_qemu_write(void *opaque, hwaddr addr, uint64_t val, + features |= BIT(EXTIOI_ENABLE_INT_ENCODE); + } + +- address_space_stl(&lams->as_iocsr, ++ address_space_stl(&lvms->as_iocsr, + EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG, + features, attrs, NULL); ++ break; ++ default: ++ g_assert_not_reached(); + } + + return MEMTX_OK; + } + +-static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, +- uint64_t *data, +- unsigned size, MemTxAttrs attrs) ++static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr, ++ uint64_t *data, ++ unsigned size, MemTxAttrs attrs) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(opaque); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque); + uint64_t ret = 0; + int features; + +@@ -859,10 +992,9 @@ static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, + ret = 0x11ULL; + break; + case FEATURE_REG: +- ret = 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI | +- 1ULL << IOCSRF_CSRIPI; ++ ret = BIT(IOCSRF_MSI) | BIT(IOCSRF_EXTIOI) | BIT(IOCSRF_CSRIPI); + if (kvm_enabled()) { +- ret |= 1ULL << IOCSRF_VM; ++ ret |= BIT(IOCSRF_VM); + } + break; + case VENDOR_REG: +@@ -872,31 +1004,32 @@ static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, + ret = 0x303030354133ULL; /* "3A5000" */ + break; + case MISC_FUNC_REG: +- if (!virt_is_veiointc_enabled(lams)) { ++ if (!virt_is_veiointc_enabled(lvms)) { + ret |= BIT_ULL(IOCSRM_EXTIOI_EN); + break; + } + +- features = address_space_ldl(&lams->as_iocsr, ++ features = address_space_ldl(&lvms->as_iocsr, + EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG, + attrs, NULL); + if (features & BIT(EXTIOI_ENABLE)) { + ret |= BIT_ULL(IOCSRM_EXTIOI_EN); + } +- + if (features & BIT(EXTIOI_ENABLE_INT_ENCODE)) { + ret |= BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE); + } + break; ++ default: ++ g_assert_not_reached(); + } + + *data = ret; + return MEMTX_OK; + } + +-static const MemoryRegionOps loongarch_qemu_ops = { +- .read_with_attrs = loongarch_qemu_read, +- .write_with_attrs = loongarch_qemu_write, ++static const MemoryRegionOps virt_iocsr_misc_ops = { ++ .read_with_attrs = virt_iocsr_misc_read, ++ .write_with_attrs = virt_iocsr_misc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, +@@ -908,43 +1041,87 @@ static const MemoryRegionOps loongarch_qemu_ops = { + }, + }; + +-static void loongarch_init(MachineState *machine) ++static void fw_cfg_add_memory(MachineState *ms) ++{ ++ hwaddr base, size, ram_size, gap; ++ int nb_numa_nodes, nodes; ++ NodeInfo *numa_info; ++ ++ ram_size = ms->ram_size; ++ base = VIRT_LOWMEM_BASE; ++ gap = VIRT_LOWMEM_SIZE; ++ nodes = nb_numa_nodes = ms->numa_state->num_nodes; ++ numa_info = ms->numa_state->nodes; ++ if (!nodes) { ++ nodes = 1; ++ } ++ ++ /* add fw_cfg memory map of node0 */ ++ if (nb_numa_nodes) { ++ size = numa_info[0].node_mem; ++ } else { ++ size = ram_size; ++ } ++ ++ if (size >= gap) { ++ memmap_add_entry(base, gap, 1); ++ size -= gap; ++ base = VIRT_HIGHMEM_BASE; ++ } ++ ++ if (size) { ++ memmap_add_entry(base, size, 1); ++ base += size; ++ } ++ ++ if (nodes < 2) { ++ return; ++ } ++ ++ /* add fw_cfg memory map of other nodes */ ++ if (numa_info[0].node_mem < gap && ram_size > gap) { ++ /* ++ * memory map for the maining nodes splited into two part ++ * lowram: [base, +(gap - numa_info[0].node_mem)) ++ * highram: [VIRT_HIGHMEM_BASE, +(ram_size - gap)) ++ */ ++ memmap_add_entry(base, gap - numa_info[0].node_mem, 1); ++ size = ram_size - gap; ++ base = VIRT_HIGHMEM_BASE; ++ } else { ++ size = ram_size - numa_info[0].node_mem; ++ } ++ ++ if (size) ++ memmap_add_entry(base, size, 1); ++} ++ ++static void virt_init(MachineState *machine) + { + LoongArchCPU *lacpu; + const char *cpu_model = machine->cpu_type; +- ram_addr_t offset = 0; +- ram_addr_t ram_size = machine->ram_size; +- uint64_t highram_size = 0, phyAddr = 0; + MemoryRegion *address_space_mem = get_system_memory(); +- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); +- int nb_numa_nodes = machine->numa_state->num_nodes; +- NodeInfo *numa_info = machine->numa_state->nodes; ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + int i; +- hwaddr fdt_base; ++ hwaddr base, size, ram_size = machine->ram_size; + const CPUArchIdList *possible_cpus; + MachineClass *mc = MACHINE_GET_CLASS(machine); + CPUState *cpu; +- char *ramName = NULL; +- struct loaderparams loaderparams = { }; + + if (!cpu_model) { + cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); + } + +- if (ram_size < 1 * GiB) { +- error_report("ram_size must be greater than 1G."); +- exit(1); +- } +- create_fdt(lams); ++ create_fdt(lvms); + + /* Create IOCSR space */ +- memory_region_init_io(&lams->system_iocsr, OBJECT(machine), NULL, ++ memory_region_init_io(&lvms->system_iocsr, OBJECT(machine), NULL, + machine, "iocsr", UINT64_MAX); +- address_space_init(&lams->as_iocsr, &lams->system_iocsr, "IOCSR"); +- memory_region_init_io(&lams->iocsr_mem, OBJECT(machine), +- &loongarch_qemu_ops, ++ address_space_init(&lvms->as_iocsr, &lvms->system_iocsr, "IOCSR"); ++ memory_region_init_io(&lvms->iocsr_mem, OBJECT(machine), ++ &virt_iocsr_misc_ops, + machine, "iocsr_misc", 0x428); +- memory_region_add_subregion(&lams->system_iocsr, 0, &lams->iocsr_mem); ++ memory_region_add_subregion(&lvms->system_iocsr, 0, &lvms->iocsr_mem); + + /* Init CPUs */ + possible_cpus = mc->possible_cpu_arch_ids(machine); +@@ -955,49 +1132,32 @@ static void loongarch_init(MachineState *machine) + lacpu = LOONGARCH_CPU(cpu); + lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id; + } +- fdt_add_cpu_nodes(lams); ++ fdt_add_cpu_nodes(lvms); ++ fdt_add_memory_nodes(machine); ++ fw_cfg_add_memory(machine); + + /* Node0 memory */ +- memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1); +- fdt_add_memory_node(machine, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 0); +- memory_region_init_alias(&lams->lowmem, NULL, "loongarch.node0.lowram", +- machine->ram, offset, VIRT_LOWMEM_SIZE); +- memory_region_add_subregion(address_space_mem, phyAddr, &lams->lowmem); +- +- offset += VIRT_LOWMEM_SIZE; +- if (nb_numa_nodes > 0) { +- assert(numa_info[0].node_mem > VIRT_LOWMEM_SIZE); +- highram_size = numa_info[0].node_mem - VIRT_LOWMEM_SIZE; +- } else { +- highram_size = ram_size - VIRT_LOWMEM_SIZE; ++ size = ram_size; ++ base = VIRT_LOWMEM_BASE; ++ if (size > VIRT_LOWMEM_SIZE) { ++ size = VIRT_LOWMEM_SIZE; + } +- phyAddr = VIRT_HIGHMEM_BASE; +- memmap_add_entry(phyAddr, highram_size, 1); +- fdt_add_memory_node(machine, phyAddr, highram_size, 0); +- memory_region_init_alias(&lams->highmem, NULL, "loongarch.node0.highram", +- machine->ram, offset, highram_size); +- memory_region_add_subregion(address_space_mem, phyAddr, &lams->highmem); +- +- /* Node1 - Nodemax memory */ +- offset += highram_size; +- phyAddr += highram_size; +- +- for (i = 1; i < nb_numa_nodes; i++) { +- MemoryRegion *nodemem = g_new(MemoryRegion, 1); +- ramName = g_strdup_printf("loongarch.node%d.ram", i); +- memory_region_init_alias(nodemem, NULL, ramName, machine->ram, +- offset, numa_info[i].node_mem); +- memory_region_add_subregion(address_space_mem, phyAddr, nodemem); +- memmap_add_entry(phyAddr, numa_info[i].node_mem, 1); +- fdt_add_memory_node(machine, phyAddr, numa_info[i].node_mem, i); +- offset += numa_info[i].node_mem; +- phyAddr += numa_info[i].node_mem; ++ ++ memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.lowram", ++ machine->ram, base, size); ++ memory_region_add_subregion(address_space_mem, base, &lvms->lowmem); ++ base += size; ++ if (ram_size - size) { ++ base = VIRT_HIGHMEM_BASE; ++ memory_region_init_alias(&lvms->highmem, NULL, "loongarch.highram", ++ machine->ram, VIRT_LOWMEM_BASE + size, ram_size - size); ++ memory_region_add_subregion(address_space_mem, base, &lvms->highmem); ++ base += ram_size - size; + } + + /* initialize device memory address space */ + if (machine->ram_size < machine->maxram_size) { + ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size; +- hwaddr device_mem_base; + + if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) { + error_report("unsupported amount of memory slots: %"PRIu64, +@@ -1011,55 +1171,35 @@ static void loongarch_init(MachineState *machine) + "%d bytes", TARGET_PAGE_SIZE); + exit(EXIT_FAILURE); + } +- /* device memory base is the top of high memory address. */ +- device_mem_base = ROUND_UP(VIRT_HIGHMEM_BASE + highram_size, 1 * GiB); +- machine_memory_devices_init(machine, device_mem_base, device_mem_size); ++ machine_memory_devices_init(machine, base, device_mem_size); + } + + /* load the BIOS image. */ +- loongarch_firmware_init(lams); ++ virt_firmware_init(lvms); + + /* fw_cfg init */ +- lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine); +- rom_set_fw(lams->fw_cfg); +- if (lams->fw_cfg != NULL) { +- fw_cfg_add_file(lams->fw_cfg, "etc/memmap", ++ lvms->fw_cfg = virt_fw_cfg_init(ram_size, machine); ++ rom_set_fw(lvms->fw_cfg); ++ if (lvms->fw_cfg != NULL) { ++ fw_cfg_add_file(lvms->fw_cfg, "etc/memmap", + memmap_table, + sizeof(struct memmap_entry) * (memmap_entries)); + } +- fdt_add_fw_cfg_node(lams); +- loaderparams.ram_size = ram_size; +- loaderparams.kernel_filename = machine->kernel_filename; +- loaderparams.kernel_cmdline = machine->kernel_cmdline; +- loaderparams.initrd_filename = machine->initrd_filename; +- /* load the kernel. */ +- if (loaderparams.kernel_filename) { +- if (lams->bios_loaded) { +- loongarch_firmware_boot(lams, &loaderparams); +- } else { +- loongarch_direct_kernel_boot(lams, &loaderparams); +- } +- } +- fdt_add_flash_node(lams); +- /* register reset function */ +- for (i = 0; i < machine->smp.cpus; i++) { +- lacpu = LOONGARCH_CPU(qemu_get_cpu(i)); +- qemu_register_reset(reset_load_elf, lacpu); +- } ++ fdt_add_fw_cfg_node(lvms); ++ fdt_add_flash_node(lvms); ++ + /* Initialize the IO interrupt subsystem */ +- loongarch_irq_init(lams); +- fdt_add_irqchip_node(lams); +- platform_bus_add_all_fdt_nodes(machine->fdt, "/intc", ++ virt_irq_init(lvms); ++ platform_bus_add_all_fdt_nodes(machine->fdt, "/platic", + VIRT_PLATFORM_BUS_BASEADDRESS, + VIRT_PLATFORM_BUS_SIZE, + VIRT_PLATFORM_BUS_IRQ); +- lams->machine_done.notify = virt_machine_done; +- qemu_add_machine_init_done_notifier(&lams->machine_done); ++ lvms->machine_done.notify = virt_done; ++ qemu_add_machine_init_done_notifier(&lvms->machine_done); + /* connect powerdown request */ +- lams->powerdown_notifier.notify = virt_powerdown_req; +- qemu_register_powerdown_notifier(&lams->powerdown_notifier); ++ lvms->powerdown_notifier.notify = virt_powerdown_req; ++ qemu_register_powerdown_notifier(&lvms->powerdown_notifier); + +- fdt_add_pcie_node(lams); + /* + * Since lowmem region starts from 0 and Linux kernel legacy start address + * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer +@@ -1067,47 +1207,44 @@ static void loongarch_init(MachineState *machine) + * Put the FDT into the memory map as a ROM image: this will ensure + * the FDT is copied again upon reset, even if addr points into RAM. + */ +- fdt_base = 1 * MiB; +- qemu_fdt_dumpdtb(machine->fdt, lams->fdt_size); +- rom_add_blob_fixed("fdt", machine->fdt, lams->fdt_size, fdt_base); ++ qemu_fdt_dumpdtb(machine->fdt, lvms->fdt_size); ++ rom_add_blob_fixed_as("fdt", machine->fdt, lvms->fdt_size, FDT_BASE, ++ &address_space_memory); ++ qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, ++ rom_ptr_for_as(&address_space_memory, FDT_BASE, lvms->fdt_size)); ++ ++ lvms->bootinfo.ram_size = ram_size; ++ loongarch_load_kernel(machine, &lvms->bootinfo); + } + +-bool loongarch_is_acpi_enabled(LoongArchMachineState *lams) ++static void virt_get_acpi(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) + { +- if (lams->acpi == ON_OFF_AUTO_OFF) { +- return false; +- } +- return true; +-} +- +-static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name, +- void *opaque, Error **errp) +-{ +- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); +- OnOffAuto acpi = lams->acpi; ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); ++ OnOffAuto acpi = lvms->acpi; + + visit_type_OnOffAuto(v, name, &acpi, errp); + } + +-static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name, ++static void virt_set_acpi(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + +- visit_type_OnOffAuto(v, name, &lams->acpi, errp); ++ visit_type_OnOffAuto(v, name, &lvms->acpi, errp); + } + +-static void loongarch_machine_initfn(Object *obj) ++static void virt_initfn(Object *obj) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + + if (tcg_enabled()) { +- lams->veiointc = ON_OFF_AUTO_OFF; ++ lvms->veiointc = ON_OFF_AUTO_OFF; + } +- lams->acpi = ON_OFF_AUTO_AUTO; +- lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); +- lams->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); +- virt_flash_create(lams); ++ lvms->acpi = ON_OFF_AUTO_AUTO; ++ lvms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); ++ lvms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); ++ virt_flash_create(lvms); + } + + static bool memhp_type_supported(DeviceState *dev) +@@ -1123,7 +1260,7 @@ static void virt_mem_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), NULL, errp); + } + +-static void virt_machine_device_pre_plug(HotplugHandler *hotplug_dev, ++static void virt_device_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { + if (memhp_type_supported(dev)) { +@@ -1134,14 +1271,14 @@ static void virt_machine_device_pre_plug(HotplugHandler *hotplug_dev, + static void virt_mem_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); + + /* the acpi ged is always exist */ +- hotplug_handler_unplug_request(HOTPLUG_HANDLER(lams->acpi_ged), dev, ++ hotplug_handler_unplug_request(HOTPLUG_HANDLER(lvms->acpi_ged), dev, + errp); + } + +-static void virt_machine_device_unplug_request(HotplugHandler *hotplug_dev, ++static void virt_device_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { + if (memhp_type_supported(dev)) { +@@ -1152,14 +1289,14 @@ static void virt_machine_device_unplug_request(HotplugHandler *hotplug_dev, + static void virt_mem_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); + +- hotplug_handler_unplug(HOTPLUG_HANDLER(lams->acpi_ged), dev, errp); +- pc_dimm_unplug(PC_DIMM(dev), MACHINE(lams)); ++ hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, errp); ++ pc_dimm_unplug(PC_DIMM(dev), MACHINE(lvms)); + qdev_unrealize(dev); + } + +-static void virt_machine_device_unplug(HotplugHandler *hotplug_dev, ++static void virt_device_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { + if (memhp_type_supported(dev)) { +@@ -1170,35 +1307,37 @@ static void virt_machine_device_unplug(HotplugHandler *hotplug_dev, + static void virt_mem_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); + +- pc_dimm_plug(PC_DIMM(dev), MACHINE(lams)); +- hotplug_handler_plug(HOTPLUG_HANDLER(lams->acpi_ged), ++ pc_dimm_plug(PC_DIMM(dev), MACHINE(lvms)); ++ hotplug_handler_plug(HOTPLUG_HANDLER(lvms->acpi_ged), + dev, &error_abort); + } + +-static void loongarch_machine_device_plug_cb(HotplugHandler *hotplug_dev, ++static void virt_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); +- MachineClass *mc = MACHINE_GET_CLASS(lams); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ MachineClass *mc = MACHINE_GET_CLASS(lvms); ++ PlatformBusDevice *pbus; + + if (device_is_dynamic_sysbus(mc, dev)) { +- if (lams->platform_bus_dev) { +- platform_bus_link_device(PLATFORM_BUS_DEVICE(lams->platform_bus_dev), +- SYS_BUS_DEVICE(dev)); ++ if (lvms->platform_bus_dev) { ++ pbus = PLATFORM_BUS_DEVICE(lvms->platform_bus_dev); ++ platform_bus_link_device(pbus, SYS_BUS_DEVICE(dev)); + } + } else if (memhp_type_supported(dev)) { + virt_mem_plug(hotplug_dev, dev, errp); + } + } + +-static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, +- DeviceState *dev) ++static HotplugHandler *virt_get_hotplug_handler(MachineState *machine, ++ DeviceState *dev) + { + MachineClass *mc = MACHINE_GET_CLASS(machine); + + if (device_is_dynamic_sysbus(mc, dev) || ++ object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) || + memhp_type_supported(dev)) { + return HOTPLUG_HANDLER(machine); + } +@@ -1234,8 +1373,8 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + return ms->possible_cpus; + } + +-static CpuInstanceProperties +-virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index) ++static CpuInstanceProperties virt_cpu_index_to_props(MachineState *ms, ++ unsigned cpu_index) + { + MachineClass *mc = MACHINE_GET_CLASS(ms); + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); +@@ -1246,25 +1385,22 @@ virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index) + + static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx) + { +- int64_t nidx = 0; ++ int64_t socket_id; + + if (ms->numa_state->num_nodes) { +- nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes); +- if (ms->numa_state->num_nodes <= nidx) { +- nidx = ms->numa_state->num_nodes - 1; +- } ++ socket_id = ms->possible_cpus->cpus[idx].props.socket_id; ++ return socket_id % ms->numa_state->num_nodes; ++ } else { ++ return 0; + } +- return nidx; + } + +-static void loongarch_class_init(ObjectClass *oc, void *data) ++static void virt_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); + +- mc->desc = "Loongson-3A5000 LS7A1000 machine"; +- mc->init = loongarch_init; +- mc->default_ram_size = 1 * GiB; ++ mc->init = virt_init; + mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464"); + mc->default_ram_id = "loongarch.ram"; + mc->max_cpus = LOONGARCH_MAX_CPUS; +@@ -1279,35 +1415,36 @@ static void loongarch_class_init(ObjectClass *oc, void *data) + mc->numa_mem_supported = true; + mc->auto_enable_numa_with_memhp = true; + mc->auto_enable_numa_with_memdev = true; +- mc->get_hotplug_handler = virt_machine_get_hotplug_handler; ++ mc->get_hotplug_handler = virt_get_hotplug_handler; + mc->default_nic = "virtio-net-pci"; +- hc->plug = loongarch_machine_device_plug_cb; +- hc->pre_plug = virt_machine_device_pre_plug; +- hc->unplug_request = virt_machine_device_unplug_request; +- hc->unplug = virt_machine_device_unplug; ++ hc->plug = virt_device_plug_cb; ++ hc->pre_plug = virt_device_pre_plug; ++ hc->unplug_request = virt_device_unplug_request; ++ hc->unplug = virt_device_unplug; + + object_class_property_add(oc, "acpi", "OnOffAuto", +- loongarch_get_acpi, loongarch_set_acpi, ++ virt_get_acpi, virt_set_acpi, + NULL, NULL); + object_class_property_set_description(oc, "acpi", + "Enable ACPI"); + object_class_property_add(oc, "v-eiointc", "OnOffAuto", +- virt_get_veiointc, virt_set_veiointc, NULL, NULL); ++ virt_get_veiointc, virt_set_veiointc, ++ NULL, NULL); + object_class_property_set_description(oc, "v-eiointc", +- "Enable Virt Extend I/O Interrupt Controller"); ++ "Enable Virt Extend I/O Interrupt Controller."); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); + #ifdef CONFIG_TPM + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); + #endif + } + +-static const TypeInfo loongarch_machine_types[] = { ++static const TypeInfo virt_machine_types[] = { + { +- .name = TYPE_LOONGARCH_MACHINE, ++ .name = TYPE_LOONGARCH_VIRT_MACHINE, + .parent = TYPE_MACHINE, +- .instance_size = sizeof(LoongArchMachineState), +- .class_init = loongarch_class_init, +- .instance_init = loongarch_machine_initfn, ++ .instance_size = sizeof(LoongArchVirtMachineState), ++ .class_init = virt_class_init, ++ .instance_init = virt_initfn, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } +@@ -1315,4 +1452,4 @@ static const TypeInfo loongarch_machine_types[] = { + } + }; + +-DEFINE_TYPES(loongarch_machine_types) ++DEFINE_TYPES(virt_machine_types) +diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h +index 1cf5bf9..626a37d 100644 +--- a/include/hw/intc/loongarch_extioi.h ++++ b/include/hw/intc/loongarch_extioi.h +@@ -39,22 +39,22 @@ + #define EXTIOI_COREISR_END (0xB20 - APIC_OFFSET) + #define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET) + #define EXTIOI_COREMAP_END (0xD00 - APIC_OFFSET) ++#define EXTIOI_SIZE 0x800 + + #define EXTIOI_VIRT_BASE (0x40000000) + #define EXTIOI_VIRT_SIZE (0x1000) + #define EXTIOI_VIRT_FEATURES (0x0) +-#define EXTIOI_HAS_VIRT_EXTENSION (0) +-#define EXTIOI_HAS_ENABLE_OPTION (1) +-#define EXTIOI_HAS_INT_ENCODE (2) +-#define EXTIOI_HAS_CPU_ENCODE (3) +-#define EXTIOI_VIRT_HAS_FEATURES (BIT(EXTIOI_HAS_VIRT_EXTENSION) \ +- | BIT(EXTIOI_HAS_ENABLE_OPTION)\ +- | BIT(EXTIOI_HAS_INT_ENCODE) \ +- | BIT(EXTIOI_HAS_CPU_ENCODE)) ++#define EXTIOI_HAS_VIRT_EXTENSION (0) ++#define EXTIOI_HAS_ENABLE_OPTION (1) ++#define EXTIOI_HAS_INT_ENCODE (2) ++#define EXTIOI_HAS_CPU_ENCODE (3) ++#define EXTIOI_VIRT_HAS_FEATURES (BIT(EXTIOI_HAS_VIRT_EXTENSION) \ ++ | BIT(EXTIOI_HAS_ENABLE_OPTION) \ ++ | BIT(EXTIOI_HAS_CPU_ENCODE)) + #define EXTIOI_VIRT_CONFIG (0x4) +-#define EXTIOI_ENABLE (1) +-#define EXTIOI_ENABLE_INT_ENCODE (2) +-#define EXTIOI_ENABLE_CPU_ENCODE (3) ++#define EXTIOI_ENABLE (1) ++#define EXTIOI_ENABLE_INT_ENCODE (2) ++#define EXTIOI_ENABLE_CPU_ENCODE (3) + #define EXTIOI_VIRT_COREMAP_START (0x40) + #define EXTIOI_VIRT_COREMAP_END (0x240) + +diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h +new file mode 100644 +index 0000000..b3b870d +--- /dev/null ++++ b/include/hw/loongarch/boot.h +@@ -0,0 +1,119 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Definitions for LoongArch boot. ++ * ++ * Copyright (C) 2023 Loongson Technology Corporation Limited ++ */ ++ ++#ifndef HW_LOONGARCH_BOOT_H ++#define HW_LOONGARCH_BOOT_H ++ ++/* UEFI 2.10 */ ++#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 ++#define EFI_2_100_SYSTEM_TABLE_REVISION ((2<<16) | (100)) ++#define EFI_SPECIFICATION_VERSION EFI_SYSTEM_TABLE_REVISION ++#define EFI_SYSTEM_TABLE_REVISION EFI_2_100_SYSTEM_TABLE_REVISION ++ ++#define FW_VERSION 0x1 ++#define FW_PATCHLEVEL 0x0 ++ ++typedef struct { ++ uint8_t b[16]; ++} efi_guid_t QEMU_ALIGNED(8); ++ ++#define EFI_GUID(a, b, c, d...) (efi_guid_t){ { \ ++ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ ++ (b) & 0xff, ((b) >> 8) & 0xff, \ ++ (c) & 0xff, ((c) >> 8) & 0xff, d } } ++ ++#define LINUX_EFI_BOOT_MEMMAP_GUID \ ++ EFI_GUID(0x800f683f, 0xd08b, 0x423a, 0xa2, 0x93, \ ++ 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4) ++ ++#define LINUX_EFI_INITRD_MEDIA_GUID \ ++ EFI_GUID(0x5568e427, 0x68fc, 0x4f3d, 0xac, 0x74, \ ++ 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68) ++ ++#define DEVICE_TREE_GUID \ ++ EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, \ ++ 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) ++ ++struct efi_config_table { ++ efi_guid_t guid; ++ uint64_t *ptr; ++ const char name[16]; ++}; ++ ++typedef struct { ++ uint64_t signature; ++ uint32_t revision; ++ uint32_t headersize; ++ uint32_t crc32; ++ uint32_t reserved; ++} efi_table_hdr_t; ++ ++struct efi_configuration_table { ++ efi_guid_t guid; ++ void *table; ++}; ++ ++struct efi_system_table { ++ efi_table_hdr_t hdr; ++ uint64_t fw_vendor; /* physical addr of CHAR16 vendor string */ ++ uint32_t fw_revision; ++ uint64_t con_in_handle; ++ uint64_t *con_in; ++ uint64_t con_out_handle; ++ uint64_t *con_out; ++ uint64_t stderr_handle; ++ uint64_t stderr_placeholder; ++ uint64_t *runtime; ++ uint64_t *boottime; ++ uint64_t nr_tables; ++ struct efi_configuration_table *tables; ++}; ++ ++typedef struct { ++ uint32_t type; ++ uint32_t pad; ++ uint64_t phys_addr; ++ uint64_t virt_addr; ++ uint64_t num_pages; ++ uint64_t attribute; ++} efi_memory_desc_t; ++ ++struct efi_boot_memmap { ++ uint64_t map_size; ++ uint64_t desc_size; ++ uint32_t desc_ver; ++ uint64_t map_key; ++ uint64_t buff_size; ++ efi_memory_desc_t map[32]; ++}; ++ ++struct efi_initrd { ++ uint64_t base; ++ uint64_t size; ++}; ++ ++struct loongarch_boot_info { ++ uint64_t ram_size; ++ const char *kernel_filename; ++ const char *kernel_cmdline; ++ const char *initrd_filename; ++ uint64_t a0, a1, a2; ++}; ++ ++extern struct memmap_entry *memmap_table; ++extern unsigned memmap_entries; ++ ++struct memmap_entry { ++ uint64_t address; ++ uint64_t length; ++ uint32_t type; ++ uint32_t reserved; ++}; ++ ++void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info); ++ ++#endif /* HW_LOONGARCH_BOOT_H */ +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 99447fd..c373e48 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -11,15 +11,15 @@ + #include "target/loongarch/cpu.h" + #include "hw/boards.h" + #include "qemu/queue.h" +-#include "hw/intc/loongarch_ipi.h" + #include "hw/block/flash.h" ++#include "hw/loongarch/boot.h" + + #define LOONGARCH_MAX_CPUS 256 + + #define VIRT_FWCFG_BASE 0x1e020000UL + #define VIRT_BIOS_BASE 0x1c000000UL + #define VIRT_BIOS_SIZE (16 * MiB) +-#define VIRT_FLASH_SECTOR_SIZE (128 * KiB) ++#define VIRT_FLASH_SECTOR_SIZE (256 * KiB) + #define VIRT_FLASH0_BASE VIRT_BIOS_BASE + #define VIRT_FLASH0_SIZE VIRT_BIOS_SIZE + #define VIRT_FLASH1_BASE 0x1d000000UL +@@ -32,7 +32,11 @@ + #define VIRT_GED_MEM_ADDR (VIRT_GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN) + #define VIRT_GED_REG_ADDR (VIRT_GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN) + +-struct LoongArchMachineState { ++#define COMMAND_LINE_SIZE 512 ++ ++#define FDT_BASE 0x100000 ++ ++struct LoongArchVirtMachineState { + /*< private >*/ + MachineState parent_obj; + +@@ -51,17 +55,15 @@ struct LoongArchMachineState { + DeviceState *acpi_ged; + int fdt_size; + DeviceState *platform_bus_dev; +- DeviceState *extioi; + PCIBus *pci_bus; + PFlashCFI01 *flash[2]; + MemoryRegion system_iocsr; + MemoryRegion iocsr_mem; + AddressSpace as_iocsr; +- int features; ++ struct loongarch_boot_info bootinfo; + }; + +-#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") +-OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_MACHINE) +-bool loongarch_is_acpi_enabled(LoongArchMachineState *lams); +-void loongarch_acpi_setup(LoongArchMachineState *lams); ++#define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt") ++OBJECT_DECLARE_SIMPLE_TYPE(LoongArchVirtMachineState, LOONGARCH_VIRT_MACHINE) ++void loongarch_acpi_setup(LoongArchVirtMachineState *lvms); + #endif +diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h +index e753449..79d4ea8 100644 +--- a/include/hw/pci-host/ls7a.h ++++ b/include/hw/pci-host/ls7a.h +@@ -24,6 +24,8 @@ + #define VIRT_PCH_REG_BASE 0x10000000UL + #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE) + #define VIRT_PCH_MSI_ADDR_LOW 0x2FF00000UL ++#define VIRT_PCH_REG_SIZE 0x400 ++#define VIRT_PCH_MSI_SIZE 0x8 + + /* + * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot +@@ -34,17 +36,18 @@ + #define VIRT_PCH_PIC_IRQ_NUM 32 + #define VIRT_GSI_BASE 64 + #define VIRT_DEVICE_IRQS 16 ++#define VIRT_UART_COUNT 4 + #define VIRT_UART_IRQ (VIRT_GSI_BASE + 2) + #define VIRT_UART_BASE 0x1fe001e0 +-#define VIRT_UART_SIZE 0X100 +-#define VIRT_RTC_IRQ (VIRT_GSI_BASE + 3) ++#define VIRT_UART_SIZE 0x100 ++#define VIRT_RTC_IRQ (VIRT_GSI_BASE + 6) + #define VIRT_MISC_REG_BASE (VIRT_PCH_REG_BASE + 0x00080000) + #define VIRT_RTC_REG_BASE (VIRT_MISC_REG_BASE + 0x00050100) + #define VIRT_RTC_LEN 0x100 +-#define VIRT_SCI_IRQ (VIRT_GSI_BASE + 4) ++#define VIRT_SCI_IRQ (VIRT_GSI_BASE + 7) + + #define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000 + #define VIRT_PLATFORM_BUS_SIZE 0x2000000 + #define VIRT_PLATFORM_BUS_NUM_IRQS 2 +-#define VIRT_PLATFORM_BUS_IRQ (VIRT_GSI_BASE + 5) ++#define VIRT_PLATFORM_BUS_IRQ (VIRT_GSI_BASE + 8) + #endif +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index f07ed49..b5dc107 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -367,6 +367,7 @@ typedef struct CPUArchState { + uint32_t mp_state; + /* Store ipistate to access from this struct */ + DeviceState *ipistate; ++ struct loongarch_boot_info *boot_info; + #endif + } CPULoongArchState; + +-- +1.8.3.1 + diff --git a/0241-target-loongarch-Support-QMP-dump-guest-memory.patch b/0241-target-loongarch-Support-QMP-dump-guest-memory.patch new file mode 100644 index 0000000000000000000000000000000000000000..1e1130aeabf30ff36e1ca39bf705312cc73a5e81 --- /dev/null +++ b/0241-target-loongarch-Support-QMP-dump-guest-memory.patch @@ -0,0 +1,240 @@ +From 445ca6fc9d1b9108f1e9c1458c9f7b640c69d20a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Thu, 19 Sep 2024 21:08:07 +0800 +Subject: [PATCH 251/293] target/loongarch: Support QMP dump-guest-memory + +commit 32c22cc47cf9b99d53aa698c612a215609fdb6c7 upstream + +Add the support needed for creating prstatus elf notes. This allows +us to use QMP dump-guest-memory. + +Now ELF notes of LoongArch only supports general elf notes, LSX and +LASX is not supported, since it is mainly used to dump guest memory. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Tested-by: Song Gao +Message-Id: <20240822065245.2286214-1-maobibo@loongson.cn> +Signed-off-by: Song Gao + +Signed-off-by: Xianglai Li +--- + target/loongarch/arch_dump.c | 167 +++++++++++++++++++++++++++++++++++++++++++ + target/loongarch/cpu.c | 1 + + target/loongarch/internals.h | 2 + + target/loongarch/meson.build | 1 + + 4 files changed, 171 insertions(+) + create mode 100644 target/loongarch/arch_dump.c + +diff --git a/target/loongarch/arch_dump.c b/target/loongarch/arch_dump.c +new file mode 100644 +index 0000000..4986db9 +--- /dev/null ++++ b/target/loongarch/arch_dump.c +@@ -0,0 +1,167 @@ ++/* ++ * Support for writing ELF notes for LoongArch architectures ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "elf.h" ++#include "sysemu/dump.h" ++#include "internals.h" ++ ++/* struct user_pt_regs from arch/loongarch/include/uapi/asm/ptrace.h */ ++struct loongarch_user_regs { ++ uint64_t gpr[32]; ++ uint64_t pad1[1]; ++ /* Special CSR registers. */ ++ uint64_t csr_era; ++ uint64_t csr_badv; ++ uint64_t pad2[10]; ++} QEMU_PACKED; ++ ++QEMU_BUILD_BUG_ON(sizeof(struct loongarch_user_regs) != 360); ++ ++/* struct elf_prstatus from include/uapi/linux/elfcore.h */ ++struct loongarch_elf_prstatus { ++ char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */ ++ uint32_t pr_pid; ++ /* ++ * 76 == offsetof(struct elf_prstatus, pr_reg) - ++ * offsetof(struct elf_prstatus, pr_ppid) ++ */ ++ char pad2[76]; ++ struct loongarch_user_regs pr_reg; ++ uint32_t pr_fpvalid; ++ char pad3[4]; ++} QEMU_PACKED; ++ ++QEMU_BUILD_BUG_ON(sizeof(struct loongarch_elf_prstatus) != 480); ++ ++/* struct user_fp_state from arch/loongarch/include/uapi/asm/ptrace.h */ ++struct loongarch_fpu_struct { ++ uint64_t fpr[32]; ++ uint64_t fcc; ++ unsigned int fcsr; ++} QEMU_PACKED; ++ ++QEMU_BUILD_BUG_ON(sizeof(struct loongarch_fpu_struct) != 268); ++ ++struct loongarch_note { ++ Elf64_Nhdr hdr; ++ char name[8]; /* align_up(sizeof("CORE"), 4) */ ++ union { ++ struct loongarch_elf_prstatus prstatus; ++ struct loongarch_fpu_struct fpu; ++ }; ++} QEMU_PACKED; ++ ++#define LOONGARCH_NOTE_HEADER_SIZE offsetof(struct loongarch_note, prstatus) ++#define LOONGARCH_PRSTATUS_NOTE_SIZE \ ++ (LOONGARCH_NOTE_HEADER_SIZE + sizeof(struct loongarch_elf_prstatus)) ++#define LOONGARCH_PRFPREG_NOTE_SIZE \ ++ (LOONGARCH_NOTE_HEADER_SIZE + sizeof(struct loongarch_fpu_struct)) ++ ++static void loongarch_note_init(struct loongarch_note *note, DumpState *s, ++ const char *name, Elf64_Word namesz, ++ Elf64_Word type, Elf64_Word descsz) ++{ ++ memset(note, 0, sizeof(*note)); ++ ++ note->hdr.n_namesz = cpu_to_dump32(s, namesz); ++ note->hdr.n_descsz = cpu_to_dump32(s, descsz); ++ note->hdr.n_type = cpu_to_dump32(s, type); ++ ++ memcpy(note->name, name, namesz); ++} ++ ++static int loongarch_write_elf64_fprpreg(WriteCoreDumpFunction f, ++ CPULoongArchState *env, int cpuid, ++ DumpState *s) ++{ ++ struct loongarch_note note; ++ int ret, i; ++ ++ loongarch_note_init(¬e, s, "CORE", 5, NT_PRFPREG, sizeof(note.fpu)); ++ note.fpu.fcsr = cpu_to_dump64(s, env->fcsr0); ++ ++ for (i = 0; i < 8; i++) { ++ note.fpu.fcc |= env->cf[i] << (8 * i); ++ } ++ note.fpu.fcc = cpu_to_dump64(s, note.fpu.fcc); ++ ++ for (i = 0; i < 32; ++i) { ++ note.fpu.fpr[i] = cpu_to_dump64(s, env->fpr[i].vreg.UD[0]); ++ } ++ ++ ret = f(¬e, LOONGARCH_PRFPREG_NOTE_SIZE, s); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, ++ int cpuid, DumpState *s) ++{ ++ struct loongarch_note note; ++ CPULoongArchState *env = &LOONGARCH_CPU(cs)->env; ++ int ret, i; ++ ++ loongarch_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, ++ sizeof(note.prstatus)); ++ note.prstatus.pr_pid = cpu_to_dump32(s, cpuid); ++ note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1); ++ ++ for (i = 0; i < 32; ++i) { ++ note.prstatus.pr_reg.gpr[i] = cpu_to_dump64(s, env->gpr[i]); ++ } ++ note.prstatus.pr_reg.csr_era = cpu_to_dump64(s, env->CSR_ERA); ++ note.prstatus.pr_reg.csr_badv = cpu_to_dump64(s, env->CSR_BADV); ++ ret = f(¬e, LOONGARCH_PRSTATUS_NOTE_SIZE, s); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ ret = loongarch_write_elf64_fprpreg(f, env, cpuid, s); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ return ret; ++} ++ ++int cpu_get_dump_info(ArchDumpInfo *info, ++ const GuestPhysBlockList *guest_phys_blocks) ++{ ++ info->d_machine = EM_LOONGARCH; ++ info->d_endian = ELFDATA2LSB; ++ info->d_class = ELFCLASS64; ++ ++ return 0; ++} ++ ++ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) ++{ ++ size_t note_size = 0; ++ ++ if (class == ELFCLASS64) { ++ note_size = LOONGARCH_PRSTATUS_NOTE_SIZE + LOONGARCH_PRFPREG_NOTE_SIZE; ++ } ++ ++ return note_size * nr_cpus; ++} +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index c223712..20ad11d 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -827,6 +827,7 @@ static struct TCGCPUOps loongarch_tcg_ops = { + #include "hw/core/sysemu-cpu-ops.h" + + static const struct SysemuCPUOps loongarch_sysemu_ops = { ++ .write_elf64_note = loongarch_cpu_write_elf64_note, + .get_phys_page_debug = loongarch_cpu_get_phys_page_debug, + }; + +diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h +index 944153b..1a02427 100644 +--- a/target/loongarch/internals.h ++++ b/target/loongarch/internals.h +@@ -72,5 +72,7 @@ void write_fcc(CPULoongArchState *env, uint64_t val); + int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n); + int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n); + void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs); ++int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, ++ int cpuid, DumpState *s); + + #endif +diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build +index e002e9a..7817318 100644 +--- a/target/loongarch/meson.build ++++ b/target/loongarch/meson.build +@@ -8,6 +8,7 @@ loongarch_ss.add(files( + + loongarch_system_ss = ss.source_set() + loongarch_system_ss.add(files( ++ 'arch_dump.c', + 'cpu_helper.c', + 'loongarch-qmp-cmds.c', + 'machine.c', +-- +1.8.3.1 + diff --git a/0242-target-loongarch-Add-compatible-support-about-VM-reb.patch b/0242-target-loongarch-Add-compatible-support-about-VM-reb.patch new file mode 100644 index 0000000000000000000000000000000000000000..a1e7ddc9f6a158223ecabf3e9a706ed1bd139a36 --- /dev/null +++ b/0242-target-loongarch-Add-compatible-support-about-VM-reb.patch @@ -0,0 +1,54 @@ +From 8c93a158e1203d34342f400b807ba5a3674a3a64 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Fri, 20 Sep 2024 08:46:31 +0800 +Subject: [PATCH 252/293] target/loongarch: Add compatible support about VM + reboot + +commit a840d70ee474c514b939f6f16fd51396c73d01c7 upstream + +With edk2-stable202408 LoongArch UEFI bios, CSR PGD register is set only +if its value is equal to zero for boot cpu, it causes reboot issue. Since +CSR PGD register is changed with linux kernel, UEFI BIOS cannot use it. + +Add workaround to clear CSR registers relative with TLB in function +loongarch_cpu_reset_hold(), so that VM can reboot with edk2-stable202408 +UEFI bios. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240827035807.3326293-1-maobibo@loongson.cn> +Signed-off-by: Song Gao + +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 20ad11d..a196235 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -556,6 +556,20 @@ static void loongarch_cpu_reset_hold(Object *obj) + env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); + env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0); + env->CSR_TID = cs->cpu_index; ++ /* ++ * Workaround for edk2-stable202408, CSR PGD register is set only if ++ * its value is equal to zero for boot cpu, it causes reboot issue. ++ * ++ * Here clear CSR registers relative with TLB. ++ */ ++ env->CSR_PGDH = 0; ++ env->CSR_PGDL = 0; ++ env->CSR_PWCL = 0; ++ env->CSR_PWCH = 0; ++ env->CSR_STLBPS = 0; ++ env->CSR_EENTRY = 0; ++ env->CSR_TLBRENTRY = 0; ++ env->CSR_MERRENTRY = 0; + + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); +-- +1.8.3.1 + diff --git a/0243-target-loongarch-kvm-Add-vCPU-reset-function.patch b/0243-target-loongarch-kvm-Add-vCPU-reset-function.patch new file mode 100644 index 0000000000000000000000000000000000000000..7d9ec09f266cce7d19ee4b6a031de8dfda79c6ea --- /dev/null +++ b/0243-target-loongarch-kvm-Add-vCPU-reset-function.patch @@ -0,0 +1,70 @@ +From b4a015628ef073925aedd41636c19c38177710cd Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Fri, 20 Sep 2024 08:48:08 +0800 +Subject: [PATCH 253/293] target/loongarch/kvm: Add vCPU reset function + +commit a724f5a84ef027cd481a18eda67ea2de58282c3e upstream + +KVM provides interface KVM_REG_LOONGARCH_VCPU_RESET to reset vCPU, +it can be used to clear internal state about kvm kernel. vCPU reset +function is added here for kvm mode. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240822022827.2273534-1-maobibo@loongson.cn> +Signed-off-by: Song Gao + +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 2 +- + target/loongarch/kvm/kvm.c | 5 ++++- + target/loongarch/kvm/kvm_loongarch.h | 2 +- + 3 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index a196235..8fb8195 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -587,7 +587,7 @@ static void loongarch_cpu_reset_hold(Object *obj) + env->pc = 0x1c000000; + memset(env->tlb, 0, sizeof(env->tlb)); + if (kvm_enabled()) { +- kvm_arch_reset_vcpu(env); ++ kvm_arch_reset_vcpu(cs); + } + #endif + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 3306cb5..30ce4d7 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -485,9 +485,12 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs) + return ret; + } + +-void kvm_arch_reset_vcpu(CPULoongArchState *env) ++void kvm_arch_reset_vcpu(CPUState *cs) + { ++ CPULoongArchState *env = cpu_env(cs); ++ + env->mp_state = KVM_MP_STATE_RUNNABLE; ++ kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, 0); + } + + static int kvm_loongarch_get_mpstate(CPUState *cs) +diff --git a/target/loongarch/kvm/kvm_loongarch.h b/target/loongarch/kvm/kvm_loongarch.h +index bdb4f18..506a5c9 100644 +--- a/target/loongarch/kvm/kvm_loongarch.h ++++ b/target/loongarch/kvm/kvm_loongarch.h +@@ -11,7 +11,7 @@ + #define QEMU_KVM_LOONGARCH_H + + int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level); +-void kvm_arch_reset_vcpu(CPULoongArchState *env); ++void kvm_arch_reset_vcpu(CPUState *cs); + + #ifdef CONFIG_KVM + /* +-- +1.8.3.1 + diff --git a/0244-acpi-ged-Add-macro-for-acpi-sleep-control-register.patch b/0244-acpi-ged-Add-macro-for-acpi-sleep-control-register.patch new file mode 100644 index 0000000000000000000000000000000000000000..60ec46f6e7a007b394b2f4c77f798cc1f68b34d8 --- /dev/null +++ b/0244-acpi-ged-Add-macro-for-acpi-sleep-control-register.patch @@ -0,0 +1,57 @@ +From 26a032f50241c971f94c40a9921694ef065d6712 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 18 Sep 2024 09:42:05 +0800 +Subject: [PATCH 254/293] acpi: ged: Add macro for acpi sleep control register + +Macro definition is added for acpi sleep control register, ged emulation +driver can use the macro , also it can be used in FDT table if ged is +exposed with FDT table. + +Signed-off-by: Bibo Mao +Reviewed-by: Igor Mammedov +Message-Id: <20240918014206.2165821-2-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/acpi/generic_event_device.c | 6 +++--- + include/hw/acpi/generic_event_device.h | 7 +++++-- + 2 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index a3d3163..889ae96 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -197,9 +197,9 @@ static void ged_regs_write(void *opaque, hwaddr addr, uint64_t data, + + switch (addr) { + case ACPI_GED_REG_SLEEP_CTL: +- slp_typ = (data >> 2) & 0x07; +- slp_en = (data >> 5) & 0x01; +- if (slp_en && slp_typ == 5) { ++ slp_typ = (data >> ACPI_GED_SLP_TYP_POS) & ACPI_GED_SLP_TYP_MASK; ++ slp_en = !!(data & ACPI_GED_SLP_EN); ++ if (slp_en && slp_typ == ACPI_GED_SLP_TYP_S5) { + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } + return; +diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h +index ba84ce0..3006916 100644 +--- a/include/hw/acpi/generic_event_device.h ++++ b/include/hw/acpi/generic_event_device.h +@@ -80,8 +80,11 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED) + /* ACPI_GED_REG_RESET value for reset*/ + #define ACPI_GED_RESET_VALUE 0x42 + +-/* ACPI_GED_REG_SLEEP_CTL.SLP_TYP value for S5 (aka poweroff) */ +-#define ACPI_GED_SLP_TYP_S5 0x05 ++/* [ACPI 5.0 Chapter 4.8.3.7] Sleep Control and Status Register */ ++#define ACPI_GED_SLP_TYP_POS 0x2 /* SLP_TYPx Bit Offset */ ++#define ACPI_GED_SLP_TYP_MASK 0x07 /* SLP_TYPx 3-bit mask */ ++#define ACPI_GED_SLP_TYP_S5 0x05 /* System _S5 State (Soft Off) */ ++#define ACPI_GED_SLP_EN 0x20 /* SLP_EN write-only bit */ + + #define GED_DEVICE "GED" + #define AML_GED_EVT_REG "EREG" +-- +1.8.3.1 + diff --git a/0245-hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch b/0245-hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch new file mode 100644 index 0000000000000000000000000000000000000000..510d489eebc424cb73de19b5a28c2c500bcbd340 --- /dev/null +++ b/0245-hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch @@ -0,0 +1,84 @@ +From aefe3c66d895b51b3fd209fcc78ed44e2d55677b Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 18 Sep 2024 09:42:06 +0800 +Subject: [PATCH 255/293] hw/loongarch/virt: Add FDT table support with acpi + ged pm register + +ACPI ged is used for power management on LoongArch virt platform, in +general it is parsed from acpi table. However if system boot directly from +elf kernel, no UEFI bios is provided and acpi table cannot be used also. + +Here acpi ged pm register is exposed with FDT table, it is compatbile +with syscon method in FDT table, only that acpi ged pm register is accessed +with 8-bit mode, rather with 32-bit mode. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Tested-by: Song Gao +Message-Id: <20240918014206.2165821-3-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 39 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 4e77901..0866022 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -280,6 +280,44 @@ static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms, + g_free(nodename); + } + ++static void fdt_add_ged_reset(LoongArchVirtMachineState *lvms) ++{ ++ char *name; ++ uint32_t ged_handle; ++ MachineState *ms = MACHINE(lvms); ++ hwaddr base = VIRT_GED_REG_ADDR; ++ hwaddr size = ACPI_GED_REG_COUNT; ++ ++ ged_handle = qemu_fdt_alloc_phandle(ms->fdt); ++ name = g_strdup_printf("/ged@%" PRIx64, base); ++ qemu_fdt_add_subnode(ms->fdt, name); ++ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon"); ++ qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, base, 0x0, size); ++ /* 8 bit registers */ ++ qemu_fdt_setprop_cell(ms->fdt, name, "reg-shift", 0); ++ qemu_fdt_setprop_cell(ms->fdt, name, "reg-io-width", 1); ++ qemu_fdt_setprop_cell(ms->fdt, name, "phandle", ged_handle); ++ ged_handle = qemu_fdt_get_phandle(ms->fdt, name); ++ g_free(name); ++ ++ name = g_strdup_printf("/reboot"); ++ qemu_fdt_add_subnode(ms->fdt, name); ++ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot"); ++ qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle); ++ qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_RESET); ++ qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_RESET_VALUE); ++ g_free(name); ++ ++ name = g_strdup_printf("/poweroff"); ++ qemu_fdt_add_subnode(ms->fdt, name); ++ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff"); ++ qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle); ++ qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_SLEEP_CTL); ++ qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_SLP_EN | ++ (ACPI_GED_SLP_TYP_S5 << ACPI_GED_SLP_TYP_POS)); ++ g_free(name); ++} ++ + static void fdt_add_uart_node(LoongArchVirtMachineState *lvms, + uint32_t *pch_pic_phandle, hwaddr base, + int irq, bool chosen) +@@ -737,6 +775,7 @@ static void virt_devices_init(DeviceState *pch_pic, + qdev_get_gpio_in(pch_pic, + VIRT_RTC_IRQ - VIRT_GSI_BASE)); + fdt_add_rtc_node(lvms, pch_pic_phandle); ++ fdt_add_ged_reset(lvms); + + /* acpi ged */ + lvms->acpi_ged = create_acpi_ged(pch_pic, lvms); +-- +1.8.3.1 + diff --git a/0246-target-loongarch-Avoid-bits-shift-exceeding-width-of.patch b/0246-target-loongarch-Avoid-bits-shift-exceeding-width-of.patch new file mode 100644 index 0000000000000000000000000000000000000000..b9acca0cc14b263dc822713ea8cbb3152cd2fba5 --- /dev/null +++ b/0246-target-loongarch-Avoid-bits-shift-exceeding-width-of.patch @@ -0,0 +1,42 @@ +From d68ae5b853de6af35bcc601d548db09745e300ef Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sat, 14 Sep 2024 14:46:45 +0800 +Subject: [PATCH 256/293] target/loongarch: Avoid bits shift exceeding width of + bool type + +Variable env->cf[i] is defined as bool type, it is treated as int type +with shift operation. However the max possible width is 56 for the shift +operation, exceeding the width of int type. And there is existing api +read_fcc() which is converted to u64 type with bitwise shift, it can be +used to dump fp registers into coredump note segment. + +Resolves: Coverity CID 1561133 +Signed-off-by: Bibo Mao +Reviewed-by: Richard Henderson +Message-Id: <20240914064645.2099169-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/arch_dump.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/target/loongarch/arch_dump.c b/target/loongarch/arch_dump.c +index 4986db9..d9e1120 100644 +--- a/target/loongarch/arch_dump.c ++++ b/target/loongarch/arch_dump.c +@@ -97,11 +97,7 @@ static int loongarch_write_elf64_fprpreg(WriteCoreDumpFunction f, + + loongarch_note_init(¬e, s, "CORE", 5, NT_PRFPREG, sizeof(note.fpu)); + note.fpu.fcsr = cpu_to_dump64(s, env->fcsr0); +- +- for (i = 0; i < 8; i++) { +- note.fpu.fcc |= env->cf[i] << (8 * i); +- } +- note.fpu.fcc = cpu_to_dump64(s, note.fpu.fcc); ++ note.fpu.fcc = cpu_to_dump64(s, read_fcc(env)); + + for (i = 0; i < 32; ++i) { + note.fpu.fpr[i] = cpu_to_dump64(s, env->fpr[i].vreg.UD[0]); +-- +1.8.3.1 + diff --git a/0247-target-loongarch-Add-loongson-binary-translation-fea.patch b/0247-target-loongarch-Add-loongson-binary-translation-fea.patch new file mode 100644 index 0000000000000000000000000000000000000000..aca61f009a6e6fe42663141ec59f81a1542e5880 --- /dev/null +++ b/0247-target-loongarch-Add-loongson-binary-translation-fea.patch @@ -0,0 +1,223 @@ +From 684d6e0fb7ce89282e763dc8f2cdc829c5faefa9 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sun, 29 Sep 2024 15:04:04 +0800 +Subject: [PATCH 257/293] target/loongarch: Add loongson binary translation + feature + +Loongson Binary Translation (LBT) is used to accelerate binary +translation, which contains 4 scratch registers (scr0 to scr3), x86/ARM +eflags (eflags) and x87 fpu stack pointer (ftop). + +Now LBT feature is added in kvm mode, not supported in TCG mode since +it is not emulated. Feature variable lbt is added with OnOffAuto type, +If lbt feature is not supported with KVM host, it reports error if there +is lbt=on command line. + +If there is no any command line about lbt parameter, it checks whether +KVM host supports lbt feature and set the corresponding value in cpucfg. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240929070405.235200-2-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 22 +++++++++++ + target/loongarch/cpu.h | 4 +- + target/loongarch/kvm/kvm.c | 73 +++++++++++++++++++++++++++-------- + target/loongarch/loongarch-qmp-cmds.c | 2 +- + 4 files changed, 82 insertions(+), 19 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 8fb8195..4eecd6f 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -708,6 +708,18 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp) + } + } + ++static bool loongarch_get_lbt(Object *obj, Error **errp) ++{ ++ return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF; ++} ++ ++static void loongarch_set_lbt(Object *obj, bool value, Error **errp) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(obj); ++ ++ cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; ++} ++ + static bool loongarch_get_pmu(Object *obj, Error **errp) + { + return LOONGARCH_CPU(obj)->pmu != ON_OFF_AUTO_OFF; +@@ -728,6 +740,16 @@ void loongarch_cpu_post_init(Object *obj) + loongarch_set_lsx); + object_property_add_bool(obj, "lasx", loongarch_get_lasx, + loongarch_set_lasx); ++ /* lbt is enabled only in kvm mode, not supported in tcg mode */ ++ if (kvm_enabled()) { ++ cpu->lbt = ON_OFF_AUTO_AUTO; ++ object_property_add_bool(obj, "lbt", loongarch_get_lbt, ++ loongarch_set_lbt); ++ object_property_set_description(obj, "lbt", ++ "Set off to disable Binary Tranlation."); ++ } else { ++ cpu->lbt = ON_OFF_AUTO_OFF; ++ } + + if (kvm_enabled()) { + cpu->pmu = ON_OFF_AUTO_AUTO; +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index b5dc107..a0cc9b5 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -156,6 +156,7 @@ FIELD(CPUCFG2, LLFTP_VER, 15, 3) + FIELD(CPUCFG2, LBT_X86, 18, 1) + FIELD(CPUCFG2, LBT_ARM, 19, 1) + FIELD(CPUCFG2, LBT_MIPS, 20, 1) ++FIELD(CPUCFG2, LBT_ALL, 18, 3) + FIELD(CPUCFG2, LSPW, 21, 1) + FIELD(CPUCFG2, LAM, 22, 1) + +@@ -283,7 +284,7 @@ struct LoongArchTLB { + typedef struct LoongArchTLB LoongArchTLB; + + enum loongarch_features { +- LOONGARCH_FEATURE_PMU, ++ LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */ + }; + + typedef struct CPUArchState { +@@ -383,6 +384,7 @@ struct ArchCPU { + CPULoongArchState env; + QEMUTimer timer; + uint32_t phy_id; ++ OnOffAuto lbt; + OnOffAuto pmu; + + /* 'compatible' string for this CPU for Linux device trees */ +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 30ce4d7..4cf3788 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -9,6 +9,7 @@ + #include + #include + ++#include "qapi/error.h" + #include "qemu/timer.h" + #include "qemu/error-report.h" + #include "qemu/main-loop.h" +@@ -683,17 +684,71 @@ static void kvm_loongarch_vm_stage_change(void *opaque, bool running, + } + } + ++static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature) ++{ ++ int ret; ++ struct kvm_device_attr attr; ++ ++ switch (feature) { ++ case LOONGARCH_FEATURE_LBT: ++ /* ++ * Return all if all the LBT features are supported such as: ++ * KVM_LOONGARCH_VM_FEAT_X86BT ++ * KVM_LOONGARCH_VM_FEAT_ARMBT ++ * KVM_LOONGARCH_VM_FEAT_MIPSBT ++ */ ++ attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; ++ attr.attr = KVM_LOONGARCH_VM_FEAT_X86BT; ++ ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); ++ attr.attr = KVM_LOONGARCH_VM_FEAT_ARMBT; ++ ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); ++ attr.attr = KVM_LOONGARCH_VM_FEAT_MIPSBT; ++ ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); ++ return (ret == 0); ++ default: ++ return false; ++ } ++} ++ ++static int kvm_cpu_check_lbt(CPUState *cs, Error **errp) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ LoongArchCPU *cpu = LOONGARCH_CPU(cs); ++ bool kvm_supported; ++ ++ kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LBT); ++ if (cpu->lbt == ON_OFF_AUTO_ON) { ++ if (kvm_supported) { ++ env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7); ++ } else { ++ error_setg(errp, "'lbt' feature not supported by KVM on this host"); ++ return -ENOTSUP; ++ } ++ } else if ((cpu->lbt == ON_OFF_AUTO_AUTO) && kvm_supported) { ++ env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7); ++ } ++ ++ return 0; ++} ++ + int kvm_arch_init_vcpu(CPUState *cs) + { + uint64_t val; ++ int ret; ++ Error *local_err = NULL; + ++ ret = 0; + qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs); + + if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, &val)) { + brk_insn = val; + } + +- return 0; ++ ret = kvm_cpu_check_lbt(cs, &local_err); ++ if (ret < 0) { ++ error_report_err(local_err); ++ } ++ return ret; + } + + int kvm_arch_destroy_vcpu(CPUState *cs) +@@ -883,22 +938,6 @@ int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level) + return kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); + } + +-bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature) +-{ +- struct kvm_device_attr attr; +- int ret; +- +- switch (feature) { +- case LOONGARCH_FEATURE_PMU: +- attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; +- attr.attr = KVM_LOONGARCH_VM_FEAT_PMU; +- ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); +- return (ret == 0); +- default: +- return false; +- } +-} +- + void kvm_arch_accel_class_init(ObjectClass *oc) + { + } +diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c +index de92ec6..dc78a3f 100644 +--- a/target/loongarch/loongarch-qmp-cmds.c ++++ b/target/loongarch/loongarch-qmp-cmds.c +@@ -42,7 +42,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) + } + + static const char *cpu_model_advertised_features[] = { +- "lsx", "lasx", "pmu", NULL ++ "lsx", "lasx", "lbt", "pmu", NULL + }; + + CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, +-- +1.8.3.1 + diff --git a/0248-target-loongarch-Implement-lbt-registers-save-restor.patch b/0248-target-loongarch-Implement-lbt-registers-save-restor.patch new file mode 100644 index 0000000000000000000000000000000000000000..951337ef55ae636d99565b645309ef8f7c850b55 --- /dev/null +++ b/0248-target-loongarch-Implement-lbt-registers-save-restor.patch @@ -0,0 +1,184 @@ +From 8867580f618a28bf58d665bc045898d825ef7715 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sun, 29 Sep 2024 15:04:05 +0800 +Subject: [PATCH 258/293] target/loongarch: Implement lbt registers + save/restore function + +Six registers scr0 - scr3, eflags and ftop are added in percpu vmstate. +And two functions kvm_loongarch_get_lbt/kvm_loongarch_put_lbt are added +to save/restore lbt registers. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240929070405.235200-3-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.h | 12 +++++++++ + target/loongarch/kvm/kvm.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++ + target/loongarch/machine.c | 25 +++++++++++++++++++ + 3 files changed, 99 insertions(+) + +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index a0cc9b5..41f9521 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -287,6 +287,17 @@ enum loongarch_features { + LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */ + }; + ++typedef struct LoongArchBT { ++ /* scratch registers */ ++ uint64_t scr0; ++ uint64_t scr1; ++ uint64_t scr2; ++ uint64_t scr3; ++ /* loongarch eflags */ ++ uint32_t eflags; ++ uint32_t ftop; ++} lbt_t; ++ + typedef struct CPUArchState { + uint64_t gpr[32]; + uint64_t pc; +@@ -296,6 +307,7 @@ typedef struct CPUArchState { + bool cf[8]; + + uint32_t fcsr0; ++ lbt_t lbt; + uint32_t fcsr0_mask; + + uint32_t cpucfg[21]; +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 4cf3788..111ef50 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -486,6 +486,58 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs) + return ret; + } + ++static int kvm_loongarch_put_lbt(CPUState *cs) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ uint64_t val; ++ int ret; ++ ++ /* check whether vm support LBT firstly */ ++ if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) { ++ return 0; ++ } ++ ++ /* set six LBT registers including scr0-scr3, eflags, ftop */ ++ ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, &env->lbt.scr0); ++ ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, &env->lbt.scr1); ++ ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, &env->lbt.scr2); ++ ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, &env->lbt.scr3); ++ /* ++ * Be cautious, KVM_REG_LOONGARCH_LBT_FTOP is defined as 64-bit however ++ * lbt.ftop is 32-bit; the same with KVM_REG_LOONGARCH_LBT_EFLAGS register ++ */ ++ val = env->lbt.eflags; ++ ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, &val); ++ val = env->lbt.ftop; ++ ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, &val); ++ ++ return ret; ++} ++ ++static int kvm_loongarch_get_lbt(CPUState *cs) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ uint64_t val; ++ int ret; ++ ++ /* check whether vm support LBT firstly */ ++ if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) { ++ return 0; ++ } ++ ++ /* get six LBT registers including scr0-scr3, eflags, ftop */ ++ ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, &env->lbt.scr0); ++ ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, &env->lbt.scr1); ++ ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, &env->lbt.scr2); ++ ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, &env->lbt.scr3); ++ ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, &val); ++ env->lbt.eflags = (uint32_t)val; ++ ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, &val); ++ env->lbt.ftop = (uint32_t)val; ++ ++ return ret; ++} ++ + void kvm_arch_reset_vcpu(CPUState *cs) + { + CPULoongArchState *env = cpu_env(cs); +@@ -625,6 +677,11 @@ int kvm_arch_get_registers(CPUState *cs) + return ret; + } + ++ ret = kvm_loongarch_get_lbt(cs); ++ if (ret) { ++ return ret; ++ } ++ + ret = kvm_loongarch_get_mpstate(cs); + if (ret) { + return ret; +@@ -653,6 +710,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) + return ret; + } + ++ ret = kvm_loongarch_put_lbt(cs); ++ if (ret) { ++ return ret; ++ } ++ + ret = kvm_loongarch_put_mpstate(cs); + if (ret) { + return ret; +diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c +index 5a7df71..fc666a6 100644 +--- a/target/loongarch/machine.c ++++ b/target/loongarch/machine.c +@@ -109,6 +109,30 @@ static const VMStateDescription vmstate_lasx = { + }, + }; + ++static bool lbt_needed(void *opaque) ++{ ++ LoongArchCPU *cpu = opaque; ++ ++ return !!FIELD_EX64(cpu->env.cpucfg[2], CPUCFG2, LBT_ALL); ++} ++ ++static const VMStateDescription vmstate_lbt = { ++ .name = "cpu/lbt", ++ .version_id = 0, ++ .minimum_version_id = 0, ++ .needed = lbt_needed, ++ .fields = (const VMStateField[]) { ++ VMSTATE_UINT64(env.lbt.scr0, LoongArchCPU), ++ VMSTATE_UINT64(env.lbt.scr1, LoongArchCPU), ++ VMSTATE_UINT64(env.lbt.scr2, LoongArchCPU), ++ VMSTATE_UINT64(env.lbt.scr3, LoongArchCPU), ++ VMSTATE_UINT32(env.lbt.eflags, LoongArchCPU), ++ VMSTATE_UINT32(env.lbt.ftop, LoongArchCPU), ++ VMSTATE_END_OF_LIST() ++ }, ++}; ++ ++ + /* TLB state */ + const VMStateDescription vmstate_tlb = { + .name = "cpu/tlb", +@@ -199,6 +223,7 @@ const VMStateDescription vmstate_loongarch_cpu = { + &vmstate_fpu, + &vmstate_lsx, + &vmstate_lasx, ++ &vmstate_lbt, + NULL + } + }; +-- +1.8.3.1 + diff --git a/0249-target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch b/0249-target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch new file mode 100644 index 0000000000000000000000000000000000000000..73a21638e5e6f6c927cab45cdf7efaeeb66852bb --- /dev/null +++ b/0249-target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch @@ -0,0 +1,210 @@ +From 4ecd0fda563d6267e802526cb57067d8db12c102 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 18 Sep 2024 16:23:15 +0800 +Subject: [PATCH 259/293] target/loongarch/kvm: Implement LoongArch PMU + extension + +Implement PMU extension for LoongArch kvm mode. Use OnOffAuto type +variable pmu to check the PMU feature. If the PMU Feature is not supported +with KVM host, it reports error if there is pmu=on command line. + +If there is no any command line about pmu parameter, it checks whether +KVM host supports the PMU Feature and set the corresponding value in cpucfg. + +This patch is based on lbt patch located at + https://lore.kernel.org/qemu-devel/20240904061859.86615-1-maobibo@loongson.cn + +Co-developed-by: Song Gao +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240918082315.2345034-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 42 +++--------------------------------- + target/loongarch/cpu.h | 1 + + target/loongarch/kvm/kvm.c | 41 +++++++++++++++++++++++++++++++++++ + target/loongarch/kvm/kvm_loongarch.h | 16 -------------- + 4 files changed, 45 insertions(+), 55 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 4eecd6f..130b0c7 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -602,35 +602,6 @@ static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info) + info->print_insn = print_insn_loongarch; + } + +-static void loongarch_cpu_check_pmu(CPUState *cs, Error **errp) +-{ +- LoongArchCPU *cpu = LOONGARCH_CPU(cs); +- bool kvm_supported; +- +- kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PMU); +- if (cpu->pmu == ON_OFF_AUTO_ON) { +- if (kvm_supported) { +- cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, 1); +- cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMNUM, 3); +- cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMBITS, 63); +- cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, UPM, 1); +- } else { +- error_setg(errp, "'pmu' feature not supported by KVM on this host."); +- return; +- } +- } else if ((cpu->pmu == ON_OFF_AUTO_AUTO) && kvm_supported) { +- cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, 1); +- cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMNUM, 3); +- cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMBITS, 63); +- cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, UPM, 1); +- } +-} +- +-static void loongarch_cpu_feature_realize(CPUState *cs, Error **errp) +-{ +- loongarch_cpu_check_pmu(cs, errp); +-} +- + static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) + { + CPUState *cs = CPU(dev); +@@ -644,11 +615,6 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) + } + + loongarch_cpu_register_gdb_regs_for_features(cs); +- loongarch_cpu_feature_realize(cs, &local_err); +- if (local_err != NULL) { +- error_propagate(errp, local_err); +- return; +- } + + cpu_reset(cs); + qemu_init_vcpu(cs); +@@ -747,16 +713,14 @@ void loongarch_cpu_post_init(Object *obj) + loongarch_set_lbt); + object_property_set_description(obj, "lbt", + "Set off to disable Binary Tranlation."); +- } else { +- cpu->lbt = ON_OFF_AUTO_OFF; +- } + +- if (kvm_enabled()) { + cpu->pmu = ON_OFF_AUTO_AUTO; + object_property_add_bool(obj, "pmu", loongarch_get_pmu, + loongarch_set_pmu); ++ object_property_set_description(obj, "pmu", ++ "Set off to performance monitor unit."); + } else { +- cpu->pmu = ON_OFF_AUTO_OFF; ++ cpu->lbt = ON_OFF_AUTO_OFF; + } + } + +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 41f9521..a9c2693 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -285,6 +285,7 @@ typedef struct LoongArchTLB LoongArchTLB; + + enum loongarch_features { + LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */ ++ LOONGARCH_FEATURE_PMU, + }; + + typedef struct LoongArchBT { +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 111ef50..df7ae65 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -767,9 +767,18 @@ static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature) + attr.attr = KVM_LOONGARCH_VM_FEAT_MIPSBT; + ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); + return (ret == 0); ++ ++ case LOONGARCH_FEATURE_PMU: ++ attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; ++ attr.attr = KVM_LOONGARCH_VM_FEAT_PMU; ++ ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); ++ return (ret == 0); ++ + default: + return false; + } ++ ++ return false; + } + + static int kvm_cpu_check_lbt(CPUState *cs, Error **errp) +@@ -793,6 +802,32 @@ static int kvm_cpu_check_lbt(CPUState *cs, Error **errp) + return 0; + } + ++static int kvm_cpu_check_pmu(CPUState *cs, Error **errp) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(cs); ++ CPULoongArchState *env = cpu_env(cs); ++ bool kvm_supported; ++ ++ kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PMU); ++ if (cpu->pmu == ON_OFF_AUTO_ON) { ++ if (!kvm_supported) { ++ error_setg(errp, "'pmu' feature not supported by KVM on the host"); ++ return -ENOTSUP; ++ } ++ } else if (cpu->pmu != ON_OFF_AUTO_AUTO) { ++ /* disable pmu if ON_OFF_AUTO_OFF is set */ ++ kvm_supported = false; ++ } ++ ++ if (kvm_supported) { ++ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMP, 1); ++ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMNUM, 3); ++ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMBITS, 63); ++ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, UPM, 1); ++ } ++ return 0; ++} ++ + int kvm_arch_init_vcpu(CPUState *cs) + { + uint64_t val; +@@ -810,6 +845,12 @@ int kvm_arch_init_vcpu(CPUState *cs) + if (ret < 0) { + error_report_err(local_err); + } ++ ++ ret = kvm_cpu_check_pmu(cs, &local_err); ++ if (ret < 0) { ++ error_report_err(local_err); ++ } ++ + return ret; + } + +diff --git a/target/loongarch/kvm/kvm_loongarch.h b/target/loongarch/kvm/kvm_loongarch.h +index 506a5c9..1051a34 100644 +--- a/target/loongarch/kvm/kvm_loongarch.h ++++ b/target/loongarch/kvm/kvm_loongarch.h +@@ -13,20 +13,4 @@ + int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level); + void kvm_arch_reset_vcpu(CPUState *cs); + +-#ifdef CONFIG_KVM +-/* +- * kvm_feature_supported: +- * +- * Returns: true if KVM supports specified feature +- * and false otherwise. +- */ +-bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature); +-#else +-static inline bool kvm_feature_supported(CPUState *cs, +- enum loongarch_features feature) +-{ +- return false; +-} +-#endif +- + #endif +-- +1.8.3.1 + diff --git a/0250-linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch b/0250-linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch new file mode 100644 index 0000000000000000000000000000000000000000..fa86ea03208b949f570610b5b5d561c62579c064 --- /dev/null +++ b/0250-linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch @@ -0,0 +1,40 @@ +From 8bf8aa8a3f8bb2b56c2dc88ae4ff02ab7cdae6e9 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Thu, 17 Oct 2024 10:07:07 +0800 +Subject: [PATCH 260/293] linux-headers: loongarch: Add kvm_para.h and + unistd_64.h + +KVM LBT supports on LoongArch depends on the linux-header file +kvm_para.h, also unistd_64.h is required by unistd.h on LoongArch +since 6.11, otherwise there will be compiling error such as: + +linux-headers/asm/unistd.h:3:10: fatal error: asm/unistd_64.h: No such file or directory + #include + +Signed-off-by: Bibo Mao +Acked-by: Song Gao +Message-Id: <20241017020708.1728620-2-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + scripts/update-linux-headers.sh | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh +index 34295c0..88c76b8 100755 +--- a/scripts/update-linux-headers.sh ++++ b/scripts/update-linux-headers.sh +@@ -156,6 +156,10 @@ for arch in $ARCHLIST; do + cp_portable "$tmpdir/bootparam.h" \ + "$output/include/standard-headers/asm-$arch" + fi ++ if [ $arch = loongarch ]; then ++ cp "$hdrdir/include/asm/kvm_para.h" "$output/linux-headers/asm-loongarch/" ++ cp "$hdrdir/include/asm/unistd_64.h" "$output/linux-headers/asm-loongarch/" ++ fi + done + + rm -rf "$output/linux-headers/linux" +-- +1.8.3.1 + diff --git a/0251-target-loongarch-Add-steal-time-support-on-migration.patch b/0251-target-loongarch-Add-steal-time-support-on-migration.patch new file mode 100644 index 0000000000000000000000000000000000000000..d2479bbb924102fb649b393c0390ea0e194858bd --- /dev/null +++ b/0251-target-loongarch-Add-steal-time-support-on-migration.patch @@ -0,0 +1,152 @@ +From 643c325e6a3bdca7b69eee8b567a164a55ad4469 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Mon, 30 Sep 2024 14:40:40 +0800 +Subject: [PATCH 261/293] target/loongarch: Add steal time support on migration + +With pv steal time supported, VM machine needs get physical address +of each vcpu and notify new host during migration. Here two +functions kvm_get_stealtime/kvm_set_stealtime, and guest steal time +physical address is only updated on KVM_PUT_FULL_STATE stage. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240930064040.753929-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.h | 3 +++ + target/loongarch/kvm/kvm.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++ + target/loongarch/machine.c | 6 +++-- + 3 files changed, 72 insertions(+), 2 deletions(-) + +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index a9c2693..d922fe3 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -371,6 +371,9 @@ typedef struct CPUArchState { + uint64_t CSR_DBG; + uint64_t CSR_DERA; + uint64_t CSR_DSAVE; ++ struct { ++ uint64_t guest_addr; ++ } stealtime; + + #ifndef CONFIG_USER_ONLY + LoongArchTLB tlb[LOONGARCH_TLB_MAX]; +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index df7ae65..f98abf0 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -35,6 +35,55 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO + }; + ++static int kvm_get_stealtime(CPUState *cs) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ int err; ++ struct kvm_device_attr attr = { ++ .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, ++ .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, ++ .addr = (uint64_t)&env->stealtime.guest_addr, ++ }; ++ ++ err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr); ++ if (err) { ++ return 0; ++ } ++ ++ err = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, attr); ++ if (err) { ++ error_report("PVTIME: KVM_GET_DEVICE_ATTR: %s", strerror(errno)); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int kvm_set_stealtime(CPUState *cs) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ int err; ++ struct kvm_device_attr attr = { ++ .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, ++ .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, ++ .addr = (uint64_t)&env->stealtime.guest_addr, ++ }; ++ ++ err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr); ++ if (err) { ++ return 0; ++ } ++ ++ err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, attr); ++ if (err) { ++ error_report("PVTIME: KVM_SET_DEVICE_ATTR %s with gpa "TARGET_FMT_lx, ++ strerror(errno), env->stealtime.guest_addr); ++ return err; ++ } ++ ++ return 0; ++} ++ + static int kvm_loongarch_get_regs_core(CPUState *cs) + { + int ret = 0; +@@ -682,6 +731,11 @@ int kvm_arch_get_registers(CPUState *cs) + return ret; + } + ++ ret = kvm_get_stealtime(cs); ++ if (ret) { ++ return ret; ++ } ++ + ret = kvm_loongarch_get_mpstate(cs); + if (ret) { + return ret; +@@ -715,6 +769,17 @@ int kvm_arch_put_registers(CPUState *cs, int level) + return ret; + } + ++ if (level >= KVM_PUT_FULL_STATE) { ++ /* ++ * only KVM_PUT_FULL_STATE is required, kvm kernel will clear ++ * guest_addr for KVM_PUT_RESET_STATE ++ */ ++ ret = kvm_set_stealtime(cs); ++ if (ret) { ++ return ret; ++ } ++ } ++ + ret = kvm_loongarch_put_mpstate(cs); + if (ret) { + return ret; +diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c +index fc666a6..dc76845 100644 +--- a/target/loongarch/machine.c ++++ b/target/loongarch/machine.c +@@ -149,8 +149,8 @@ const VMStateDescription vmstate_tlb = { + /* LoongArch CPU state */ + const VMStateDescription vmstate_loongarch_cpu = { + .name = "cpu", +- .version_id = 2, +- .minimum_version_id = 2, ++ .version_id = 3, ++ .minimum_version_id = 3, + .fields = (VMStateField[]) { + VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32), + VMSTATE_UINTTL(env.pc, LoongArchCPU), +@@ -216,6 +216,8 @@ const VMStateDescription vmstate_loongarch_cpu = { + 0, vmstate_tlb, LoongArchTLB), + + VMSTATE_UINT64(kvm_state_counter, LoongArchCPU), ++ /* PV steal time */ ++ VMSTATE_UINT64(env.stealtime.guest_addr, LoongArchCPU), + + VMSTATE_END_OF_LIST() + }, +-- +1.8.3.1 + diff --git a/0252-sync-kernel-headers.patch b/0252-sync-kernel-headers.patch new file mode 100644 index 0000000000000000000000000000000000000000..09f4cba3ac213c7ef42c40d2cd8b2351bec007b3 --- /dev/null +++ b/0252-sync-kernel-headers.patch @@ -0,0 +1,116 @@ +From e4444965b9e1fdf8cfc86c7a748bcb28f1476b55 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Sat, 26 Oct 2024 17:08:30 +0800 +Subject: [PATCH 262/293] sync kernel headers + +Signed-off-by: Xianglai Li +--- + linux-headers/asm-loongarch/bitsperlong.h | 8 +++++++ + linux-headers/asm-loongarch/kvm.h | 40 ++++++++++++++++++++++++++++--- + linux-headers/asm-loongarch/unistd.h | 1 + + 3 files changed, 46 insertions(+), 3 deletions(-) + +diff --git a/linux-headers/asm-loongarch/bitsperlong.h b/linux-headers/asm-loongarch/bitsperlong.h +index 6dc0bb0..00b4ba1 100644 +--- a/linux-headers/asm-loongarch/bitsperlong.h ++++ b/linux-headers/asm-loongarch/bitsperlong.h +@@ -1 +1,9 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++#ifndef __ASM_LOONGARCH_BITSPERLONG_H ++#define __ASM_LOONGARCH_BITSPERLONG_H ++ ++#define __BITS_PER_LONG (__SIZEOF_LONG__ * 8) ++ + #include ++ ++#endif /* __ASM_LOONGARCH_BITSPERLONG_H */ +diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h +index b40b640..d619b94 100644 +--- a/linux-headers/asm-loongarch/kvm.h ++++ b/linux-headers/asm-loongarch/kvm.h +@@ -19,8 +19,10 @@ + + #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 + #define KVM_DIRTY_LOG_PAGE_OFFSET 64 ++#define __KVM_HAVE_IRQ_LINE + + #define KVM_GUESTDBG_USE_SW_BP 0x00010000 ++ + /* + * for KVM_GET_REGS and KVM_SET_REGS + */ +@@ -66,6 +68,7 @@ struct kvm_fpu { + #define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL) + #define KVM_REG_LOONGARCH_FPSIMD (KVM_REG_LOONGARCH | 0x30000ULL) + #define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL) ++#define KVM_REG_LOONGARCH_LBT (KVM_REG_LOONGARCH | 0x50000ULL) + #define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL) + #define KVM_CSR_IDX_MASK 0x7fff + #define KVM_CPUCFG_IDX_MASK 0x7fff +@@ -79,14 +82,34 @@ struct kvm_fpu { + /* Debugging: Special instruction for software breakpoint */ + #define KVM_REG_LOONGARCH_DEBUG_INST (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3) + ++/* LBT registers */ ++#define KVM_REG_LOONGARCH_LBT_SCR0 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 1) ++#define KVM_REG_LOONGARCH_LBT_SCR1 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 2) ++#define KVM_REG_LOONGARCH_LBT_SCR2 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 3) ++#define KVM_REG_LOONGARCH_LBT_SCR3 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 4) ++#define KVM_REG_LOONGARCH_LBT_EFLAGS (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 5) ++#define KVM_REG_LOONGARCH_LBT_FTOP (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 6) ++ + #define LOONGARCH_REG_SHIFT 3 + #define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT)) + #define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG) + #define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG) +-#define KVM_LOONGARCH_VCPU_CPUCFG 0 + +-#define KVM_LOONGARCH_VM_FEAT_CTRL 1000 +-#define KVM_LOONGARCH_VM_FEAT_PMU 1000 ++/* Device Control API on vm fd */ ++#define KVM_LOONGARCH_VM_FEAT_CTRL 0 ++#define KVM_LOONGARCH_VM_FEAT_LSX 0 ++#define KVM_LOONGARCH_VM_FEAT_LASX 1 ++#define KVM_LOONGARCH_VM_FEAT_X86BT 2 ++#define KVM_LOONGARCH_VM_FEAT_ARMBT 3 ++#define KVM_LOONGARCH_VM_FEAT_MIPSBT 4 ++#define KVM_LOONGARCH_VM_FEAT_PMU 5 ++#define KVM_LOONGARCH_VM_FEAT_PV_IPI 6 ++#define KVM_LOONGARCH_VM_FEAT_PV_STEALTIME 7 ++ ++/* Device Control API on vcpu fd */ ++#define KVM_LOONGARCH_VCPU_CPUCFG 0 ++#define KVM_LOONGARCH_VCPU_PVTIME_CTRL 1 ++#define KVM_LOONGARCH_VCPU_PVTIME_GPA 0 + + struct kvm_debug_exit_arch { + }; +@@ -113,4 +136,15 @@ struct kvm_iocsr_entry { + #define KVM_IRQCHIP_NUM_PINS 64 + #define KVM_MAX_CORES 256 + ++#define KVM_LOONGARCH_VM_HAVE_IRQCHIP 0x40000001 ++ ++#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000002 ++ ++#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000003 ++ ++#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000004 ++#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0 ++ ++#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 0x40000005 ++ + #endif /* __UAPI_ASM_LOONGARCH_KVM_H */ +diff --git a/linux-headers/asm-loongarch/unistd.h b/linux-headers/asm-loongarch/unistd.h +index fcb6689..b344b1f 100644 +--- a/linux-headers/asm-loongarch/unistd.h ++++ b/linux-headers/asm-loongarch/unistd.h +@@ -1,4 +1,5 @@ + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++#define __ARCH_WANT_NEW_STAT + #define __ARCH_WANT_SYS_CLONE + #define __ARCH_WANT_SYS_CLONE3 + +-- +1.8.3.1 + diff --git a/0253-accel-kvm-Extract-common-KVM-vCPU-creation-parking-c.patch b/0253-accel-kvm-Extract-common-KVM-vCPU-creation-parking-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..7508c965933068e2bbaeff5ea8e62996eb6b4132 --- /dev/null +++ b/0253-accel-kvm-Extract-common-KVM-vCPU-creation-parking-c.patch @@ -0,0 +1,234 @@ +From 85a7a5758fb7584de140d3847bd327362ccf0925 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:14:56 +0100 +Subject: [PATCH 263/293] accel/kvm: Extract common KVM vCPU {creation,parking} + code + +KVM vCPU creation is done once during the vCPU realization when Qemu vCPU thread +is spawned. This is common to all the architectures as of now. + +Hot-unplug of vCPU results in destruction of the vCPU object in QOM but the +corresponding KVM vCPU object in the Host KVM is not destroyed as KVM doesn't +support vCPU removal. Therefore, its representative KVM vCPU object/context in +Qemu is parked. + +Refactor architecture common logic so that some APIs could be reused by vCPU +Hotplug code of some architectures likes ARM, Loongson etc. Update new/old APIs +with trace events. New APIs qemu_{create,park,unpark}_vcpu() can be externally +called. No functional change is intended here. + +Signed-off-by: Salil Mehta +Reviewed-by: Gavin Shan +Tested-by: Vishnu Pajjuri +Reviewed-by: Jonathan Cameron +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Shaoqin Huang +Reviewed-by: Vishnu Pajjuri +Reviewed-by: Nicholas Piggin +Tested-by: Zhao Liu +Reviewed-by: Zhao Liu +Reviewed-by: Harsh Prateek Bora +Reviewed-by: Igor Mammedov +Message-Id: <20240716111502.202344-2-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + accel/kvm/kvm-all.c | 95 +++++++++++++++++++++++++++++++++----------------- + accel/kvm/trace-events | 4 +++ + include/sysemu/kvm.h | 25 +++++++++++++ + 3 files changed, 92 insertions(+), 32 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 25d23bb..169d828 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -325,14 +325,71 @@ err: + return ret; + } + ++void kvm_park_vcpu(CPUState *cpu) ++{ ++ struct KVMParkedVcpu *vcpu; ++ ++ trace_kvm_park_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu)); ++ ++ vcpu = g_malloc0(sizeof(*vcpu)); ++ vcpu->vcpu_id = kvm_arch_vcpu_id(cpu); ++ vcpu->kvm_fd = cpu->kvm_fd; ++ QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node); ++} ++ ++int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id) ++{ ++ struct KVMParkedVcpu *cpu; ++ int kvm_fd = -ENOENT; ++ ++ QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) { ++ if (cpu->vcpu_id == vcpu_id) { ++ QLIST_REMOVE(cpu, node); ++ kvm_fd = cpu->kvm_fd; ++ g_free(cpu); ++ } ++ } ++ ++ trace_kvm_unpark_vcpu(vcpu_id, kvm_fd > 0 ? "unparked" : "!found parked"); ++ ++ return kvm_fd; ++} ++ ++int kvm_create_vcpu(CPUState *cpu) ++{ ++ unsigned long vcpu_id = kvm_arch_vcpu_id(cpu); ++ KVMState *s = kvm_state; ++ int kvm_fd; ++ ++ /* check if the KVM vCPU already exist but is parked */ ++ kvm_fd = kvm_unpark_vcpu(s, vcpu_id); ++ if (kvm_fd < 0) { ++ /* vCPU not parked: create a new KVM vCPU */ ++ kvm_fd = kvm_vm_ioctl(s, KVM_CREATE_VCPU, vcpu_id); ++ if (kvm_fd < 0) { ++ error_report("KVM_CREATE_VCPU IOCTL failed for vCPU %lu", vcpu_id); ++ return kvm_fd; ++ } ++ } ++ ++ cpu->kvm_fd = kvm_fd; ++ cpu->kvm_state = s; ++ cpu->vcpu_dirty = true; ++ cpu->dirty_pages = 0; ++ cpu->throttle_us_per_full = 0; ++ ++ trace_kvm_create_vcpu(cpu->cpu_index, vcpu_id, kvm_fd); ++ ++ return 0; ++} ++ + static int do_kvm_destroy_vcpu(CPUState *cpu) + { + KVMState *s = kvm_state; + long mmap_size; +- struct KVMParkedVcpu *vcpu = NULL; + int ret = 0; + +- DPRINTF("kvm_destroy_vcpu\n"); ++ trace_kvm_destroy_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu)); + + ret = kvm_arch_destroy_vcpu(cpu); + if (ret < 0) { +@@ -358,10 +415,7 @@ static int do_kvm_destroy_vcpu(CPUState *cpu) + } + } + +- vcpu = g_malloc0(sizeof(*vcpu)); +- vcpu->vcpu_id = kvm_arch_vcpu_id(cpu); +- vcpu->kvm_fd = cpu->kvm_fd; +- QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node); ++ kvm_park_vcpu(cpu); + err: + return ret; + } +@@ -374,24 +428,6 @@ void kvm_destroy_vcpu(CPUState *cpu) + } + } + +-static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id) +-{ +- struct KVMParkedVcpu *cpu; +- +- QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) { +- if (cpu->vcpu_id == vcpu_id) { +- int kvm_fd; +- +- QLIST_REMOVE(cpu, node); +- kvm_fd = cpu->kvm_fd; +- g_free(cpu); +- return kvm_fd; +- } +- } +- +- return kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id); +-} +- + int kvm_init_vcpu(CPUState *cpu, Error **errp) + { + KVMState *s = kvm_state; +@@ -400,19 +436,14 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp) + + trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu)); + +- ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu)); ++ ret = kvm_create_vcpu(cpu); + if (ret < 0) { +- error_setg_errno(errp, -ret, "kvm_init_vcpu: kvm_get_vcpu failed (%lu)", ++ error_setg_errno(errp, -ret, ++ "kvm_init_vcpu: kvm_create_vcpu failed (%lu)", + kvm_arch_vcpu_id(cpu)); + goto err; + } + +- cpu->kvm_fd = ret; +- cpu->kvm_state = s; +- cpu->vcpu_dirty = true; +- cpu->dirty_pages = 0; +- cpu->throttle_us_per_full = 0; +- + mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); + if (mmap_size < 0) { + ret = mmap_size; +diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events +index 399aaeb..d6109f2 100644 +--- a/accel/kvm/trace-events ++++ b/accel/kvm/trace-events +@@ -9,6 +9,10 @@ kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p" + kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s" + kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s" + kvm_init_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu" ++kvm_create_vcpu(int cpu_index, unsigned long arch_cpu_id, int kvm_fd) "index: %d, id: %lu, kvm fd: %d" ++kvm_park_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu" ++kvm_destroy_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu" ++kvm_unpark_vcpu(unsigned long arch_cpu_id, const char *msg) "id: %lu %s" + kvm_irqchip_commit_routes(void) "" + kvm_irqchip_add_msi_route(char *name, int vector, int virq) "dev %s vector %d virq %d" + kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d" +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index 1e15cfe..4d00ade 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -321,6 +321,31 @@ int kvm_create_device(KVMState *s, uint64_t type, bool test); + */ + bool kvm_device_supported(int vmfd, uint64_t type); + ++/** ++ * kvm_create_vcpu - Gets a parked KVM vCPU or creates a KVM vCPU ++ * @cpu: QOM CPUState object for which KVM vCPU has to be fetched/created. ++ * ++ * @returns: 0 when success, errno (<0) when failed. ++ */ ++int kvm_create_vcpu(CPUState *cpu); ++ ++/** ++ * kvm_park_vcpu - Park QEMU KVM vCPU context ++ * @cpu: QOM CPUState object for which QEMU KVM vCPU context has to be parked. ++ * ++ * @returns: none ++ */ ++void kvm_park_vcpu(CPUState *cpu); ++ ++/** ++ * kvm_unpark_vcpu - unpark QEMU KVM vCPU context ++ * @s: KVM State ++ * @vcpu_id: Architecture vCPU ID of the parked vCPU ++ * ++ * @returns: KVM fd ++ */ ++int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id); ++ + /* Arch specific hooks */ + + extern const KVMCapabilityInfo kvm_arch_required_capabilities[]; +-- +1.8.3.1 + diff --git a/0254-hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c.patch b/0254-hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..0ed215fef8178c3dfab849f3af66c09687f9e50a --- /dev/null +++ b/0254-hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c.patch @@ -0,0 +1,62 @@ +From dde5f21c4a47595a47b2865820d8ede9d4c9b01f Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:14:57 +0100 +Subject: [PATCH 264/293] hw/acpi: Move CPU ctrl-dev MMIO region len macro to + common header file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +CPU ctrl-dev MMIO region length could be used in ACPI GED and various other +architecture specific places. Move ACPI_CPU_HOTPLUG_REG_LEN macro to more +appropriate common header file. + +Signed-off-by: Salil Mehta +Reviewed-by: Alex Bennée +Reviewed-by: Jonathan Cameron +Reviewed-by: Gavin Shan +Reviewed-by: David Hildenbrand +Reviewed-by: Shaoqin Huang +Tested-by: Vishnu Pajjuri +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Tested-by: Zhao Liu +Reviewed-by: Zhao Liu +Reviewed-by: Igor Mammedov +Message-Id: <20240716111502.202344-3-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + hw/acpi/cpu.c | 1 - + include/hw/acpi/cpu.h | 2 ++ + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index 011d2c6..1a4c2a8 100644 +--- a/hw/acpi/cpu.c ++++ b/hw/acpi/cpu.c +@@ -7,7 +7,6 @@ + #include "trace.h" + #include "sysemu/numa.h" + +-#define ACPI_CPU_HOTPLUG_REG_LEN 12 + #define ACPI_CPU_SELECTOR_OFFSET_WR 0 + #define ACPI_CPU_FLAGS_OFFSET_RW 4 + #define ACPI_CPU_CMD_OFFSET_WR 5 +diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h +index bc90166..f4a28df 100644 +--- a/include/hw/acpi/cpu.h ++++ b/include/hw/acpi/cpu.h +@@ -18,6 +18,8 @@ + #include "hw/boards.h" + #include "hw/hotplug.h" + ++#define ACPI_CPU_HOTPLUG_REG_LEN 12 ++ + typedef struct AcpiCpuStatus { + struct CPUState *cpu; + uint64_t arch_id; +-- +1.8.3.1 + diff --git a/0255-hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho.patch b/0255-hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho.patch new file mode 100644 index 0000000000000000000000000000000000000000..1d4d1f1dc00eeffff80e8c796360bdb569b154ba --- /dev/null +++ b/0255-hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho.patch @@ -0,0 +1,215 @@ +From 7948a3bd1a76f3eff1187fa838cc2f8b3bd37798 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:14:58 +0100 +Subject: [PATCH 265/293] hw/acpi: Update ACPI GED framework to support vCPU + Hotplug + +ACPI GED (as described in the ACPI 6.4 spec) uses an interrupt listed in the +_CRS object of GED to intimate OSPM about an event. Later then demultiplexes the +notified event by evaluating ACPI _EVT method to know the type of event. Use +ACPI GED to also notify the guest kernel about any CPU hot(un)plug events. + +Note, GED interface is used by many hotplug events like memory hotplug, NVDIMM +hotplug and non-hotplug events like system power down event. Each of these can +be selected using a bit in the 32 bit GED IO interface. A bit has been reserved +for the CPU hotplug event. + +ACPI CPU hotplug related initialization should only happen if ACPI_CPU_HOTPLUG +support has been enabled for particular architecture. Add cpu_hotplug_hw_init() +stub to avoid compilation break. + +Co-developed-by: Keqian Zhu +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +Reviewed-by: Jonathan Cameron +Reviewed-by: Gavin Shan +Reviewed-by: David Hildenbrand +Reviewed-by: Shaoqin Huang +Tested-by: Vishnu Pajjuri +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Vishnu Pajjuri +Tested-by: Zhao Liu +Reviewed-by: Zhao Liu +Message-Id: <20240716111502.202344-4-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Igor Mammedov +Signed-off-by: Xianglai Li +--- + docs/specs/acpi_hw_reduced_hotplug.rst | 3 ++- + hw/acpi/acpi-cpu-hotplug-stub.c | 6 +++++ + hw/acpi/generic_event_device.c | 47 ++++++++++++++++++++++++++++++++++ + include/hw/acpi/generic_event_device.h | 4 +++ + 4 files changed, 59 insertions(+), 1 deletion(-) + +diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst +index 0bd3f93..3acd6fc 100644 +--- a/docs/specs/acpi_hw_reduced_hotplug.rst ++++ b/docs/specs/acpi_hw_reduced_hotplug.rst +@@ -64,7 +64,8 @@ GED IO interface (4 byte access) + 0: Memory hotplug event + 1: System power down event + 2: NVDIMM hotplug event +- 3-31: Reserved ++ 3: CPU hotplug event ++ 4-31: Reserved + + **write_access:** + +diff --git a/hw/acpi/acpi-cpu-hotplug-stub.c b/hw/acpi/acpi-cpu-hotplug-stub.c +index 3fc4b14..c6c61bb 100644 +--- a/hw/acpi/acpi-cpu-hotplug-stub.c ++++ b/hw/acpi/acpi-cpu-hotplug-stub.c +@@ -19,6 +19,12 @@ void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner, + return; + } + ++void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, ++ CPUHotplugState *state, hwaddr base_addr) ++{ ++ return; ++} ++ + void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list) + { + return; +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 889ae96..d797df0 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -25,6 +25,7 @@ static const uint32_t ged_supported_events[] = { + ACPI_GED_MEM_HOTPLUG_EVT, + ACPI_GED_PWR_DOWN_EVT, + ACPI_GED_NVDIMM_HOTPLUG_EVT, ++ ACPI_GED_CPU_HOTPLUG_EVT, + }; + + /* +@@ -234,6 +235,8 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, + } else { + acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp); + } ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "virt: device plug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); +@@ -248,6 +251,8 @@ static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev, + if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) && + !(object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)))) { + acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); +@@ -261,6 +266,8 @@ static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev, + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + acpi_memory_unplug_cb(&s->memhp_state, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); +@@ -272,6 +279,7 @@ static void acpi_ged_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) + AcpiGedState *s = ACPI_GED(adev); + + acpi_memory_ospm_status(&s->memhp_state, list); ++ acpi_cpu_ospm_status(&s->cpuhp_state, list); + } + + static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) +@@ -286,6 +294,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) + sel = ACPI_GED_PWR_DOWN_EVT; + } else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) { + sel = ACPI_GED_NVDIMM_HOTPLUG_EVT; ++ } else if (ev & ACPI_CPU_HOTPLUG_STATUS) { ++ sel = ACPI_GED_CPU_HOTPLUG_EVT; + } else { + /* Unknown event. Return without generating interrupt. */ + warn_report("GED: Unsupported event %d. No irq injected", ev); +@@ -371,6 +381,42 @@ static const VMStateDescription vmstate_acpi_ged = { + } + }; + ++static void acpi_ged_realize(DeviceState *dev, Error **errp) ++{ ++ SysBusDevice *sbd = SYS_BUS_DEVICE(dev); ++ AcpiGedState *s = ACPI_GED(dev); ++ uint32_t ged_events; ++ int i; ++ ++ ged_events = ctpop32(s->ged_event_bitmap); ++ ++ for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) { ++ uint32_t event = s->ged_event_bitmap & ged_supported_events[i]; ++ ++ if (!event) { ++ continue; ++ } ++ ++ switch (event) { ++ case ACPI_GED_CPU_HOTPLUG_EVT: ++ /* initialize CPU Hotplug related regions */ ++ memory_region_init(&s->container_cpuhp, OBJECT(dev), ++ "cpuhp container", ++ ACPI_CPU_HOTPLUG_REG_LEN); ++ sysbus_init_mmio(sbd, &s->container_cpuhp); ++ cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev), ++ &s->cpuhp_state, 0); ++ break; ++ } ++ ged_events--; ++ } ++ ++ if (ged_events) { ++ error_report("Unsupported events specified"); ++ abort(); ++ } ++} ++ + static void acpi_ged_initfn(Object *obj) + { + DeviceState *dev = DEVICE(obj); +@@ -411,6 +457,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) + dc->desc = "ACPI Generic Event Device"; + device_class_set_props(dc, acpi_ged_properties); + dc->vmsd = &vmstate_acpi_ged; ++ dc->realize = acpi_ged_realize; + + hc->plug = acpi_ged_device_plug_cb; + hc->unplug_request = acpi_ged_unplug_request_cb; +diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h +index 3006916..c4e0e96 100644 +--- a/include/hw/acpi/generic_event_device.h ++++ b/include/hw/acpi/generic_event_device.h +@@ -62,6 +62,7 @@ + #include "hw/sysbus.h" + #include "hw/acpi/memory_hotplug.h" + #include "hw/acpi/ghes.h" ++#include "hw/acpi/cpu.h" + #include "qom/object.h" + + #define ACPI_POWER_BUTTON_DEVICE "PWRB" +@@ -98,6 +99,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED) + #define ACPI_GED_MEM_HOTPLUG_EVT 0x1 + #define ACPI_GED_PWR_DOWN_EVT 0x2 + #define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4 ++#define ACPI_GED_CPU_HOTPLUG_EVT 0x8 + + typedef struct GEDState { + MemoryRegion evt; +@@ -109,6 +111,8 @@ struct AcpiGedState { + SysBusDevice parent_obj; + MemHotplugState memhp_state; + MemoryRegion container_memhp; ++ CPUHotplugState cpuhp_state; ++ MemoryRegion container_cpuhp; + GEDState ged_state; + uint32_t ged_event_bitmap; + qemu_irq irq; +-- +1.8.3.1 + diff --git a/0256-hw-acpi-Update-GED-_EVT-method-AML-with-CPU-scan.patch b/0256-hw-acpi-Update-GED-_EVT-method-AML-with-CPU-scan.patch new file mode 100644 index 0000000000000000000000000000000000000000..6485d284af89812532bcca2c5c0000d82ffd66a3 --- /dev/null +++ b/0256-hw-acpi-Update-GED-_EVT-method-AML-with-CPU-scan.patch @@ -0,0 +1,67 @@ +From f22e0aac1d5727564e7a28cbe578592da07aaa88 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:14:59 +0100 +Subject: [PATCH 266/293] hw/acpi: Update GED _EVT method AML with CPU scan + +OSPM evaluates _EVT method to map the event. The CPU hotplug event eventually +results in start of the CPU scan. Scan figures out the CPU and the kind of +event(plug/unplug) and notifies it back to the guest. Update the GED AML _EVT +method with the call to method \\_SB.CPUS.CSCN (via \\_SB.GED.CSCN) + +Architecture specific code [1] might initialize its CPUs AML code by calling +common function build_cpus_aml() like below for ARM: + +build_cpus_aml(scope, ms, opts, xx_madt_cpu_entry, memmap[VIRT_CPUHP_ACPI].base, + "\\_SB", "\\_SB.GED.CSCN", AML_SYSTEM_MEMORY); + +[1] https://lore.kernel.org/qemu-devel/20240613233639.202896-13-salil.mehta@huawei.com/ + +Co-developed-by: Keqian Zhu +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +Reviewed-by: Jonathan Cameron +Reviewed-by: Gavin Shan +Tested-by: Vishnu Pajjuri +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Shaoqin Huang +Tested-by: Zhao Liu +Reviewed-by: Igor Mammedov +Message-Id: <20240716111502.202344-5-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + hw/acpi/generic_event_device.c | 3 +++ + include/hw/acpi/generic_event_device.h | 1 + + 2 files changed, 4 insertions(+) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index d797df0..48f03cd 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -108,6 +108,9 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, + aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "." + MEMORY_SLOT_SCAN_METHOD)); + break; ++ case ACPI_GED_CPU_HOTPLUG_EVT: ++ aml_append(if_ctx, aml_call0(AML_GED_EVT_CPU_SCAN_METHOD)); ++ break; + case ACPI_GED_PWR_DOWN_EVT: + aml_append(if_ctx, + aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), +diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h +index c4e0e96..d2dac87 100644 +--- a/include/hw/acpi/generic_event_device.h ++++ b/include/hw/acpi/generic_event_device.h +@@ -90,6 +90,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED) + #define GED_DEVICE "GED" + #define AML_GED_EVT_REG "EREG" + #define AML_GED_EVT_SEL "ESEL" ++#define AML_GED_EVT_CPU_SCAN_METHOD "\\_SB.GED.CSCN" + + /* + * Platforms need to specify the GED event bitmap +-- +1.8.3.1 + diff --git a/0257-hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change.patch b/0257-hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change.patch new file mode 100644 index 0000000000000000000000000000000000000000..e178c3967b7e3882a3d8665c40fbf9dfac5604ae --- /dev/null +++ b/0257-hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change.patch @@ -0,0 +1,110 @@ +From 6a0903c0c6ce0d3b2a833f612f5ac76b81bfb39c Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:15:00 +0100 +Subject: [PATCH 267/293] hw/acpi: Update CPUs AML with cpu-(ctrl)dev change + +CPUs Control device(\\_SB.PCI0) register interface for the x86 arch is IO port +based and existing CPUs AML code assumes _CRS objects would evaluate to a system +resource which describes IO Port address. But on ARM arch CPUs control +device(\\_SB.PRES) register interface is memory-mapped hence _CRS object should +evaluate to system resource which describes memory-mapped base address. Update +build CPUs AML function to accept both IO/MEMORY region spaces and accordingly +update the _CRS object. + +Co-developed-by: Keqian Zhu +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +Reviewed-by: Gavin Shan +Tested-by: Vishnu Pajjuri +Reviewed-by: Jonathan Cameron +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Shaoqin Huang +Tested-by: Zhao Liu +Reviewed-by: Igor Mammedov +Message-Id: <20240716111502.202344-6-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + hw/acpi/cpu.c | 17 +++++++++++++---- + hw/i386/acpi-build.c | 3 ++- + include/hw/acpi/cpu.h | 5 +++-- + 3 files changed, 18 insertions(+), 7 deletions(-) + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index 1a4c2a8..b48a0e7 100644 +--- a/hw/acpi/cpu.c ++++ b/hw/acpi/cpu.c +@@ -338,9 +338,10 @@ const VMStateDescription vmstate_cpu_hotplug = { + #define CPU_FW_EJECT_EVENT "CEJF" + + void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, +- build_madt_cpu_fn build_madt_cpu, hwaddr io_base, ++ build_madt_cpu_fn build_madt_cpu, hwaddr base_addr, + const char *res_root, +- const char *event_handler_method) ++ const char *event_handler_method, ++ AmlRegionSpace rs) + { + Aml *ifctx; + Aml *field; +@@ -364,14 +365,22 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + aml_name_decl("_UID", aml_string("CPU Hotplug resources"))); + aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0)); + ++ assert((rs == AML_SYSTEM_IO) || (rs == AML_SYSTEM_MEMORY)); ++ + crs = aml_resource_template(); +- aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1, ++ if (rs == AML_SYSTEM_IO) { ++ aml_append(crs, aml_io(AML_DECODE16, base_addr, base_addr, 1, + ACPI_CPU_HOTPLUG_REG_LEN)); ++ } else if (rs == AML_SYSTEM_MEMORY) { ++ aml_append(crs, aml_memory32_fixed(base_addr, ++ ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE)); ++ } ++ + aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs)); + + /* declare CPU hotplug MMIO region with related access fields */ + aml_append(cpu_ctrl_dev, +- aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base), ++ aml_operation_region("PRST", rs, aml_int(base_addr), + ACPI_CPU_HOTPLUG_REG_LEN)); + + field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 1e17834..0627b40 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -1546,7 +1546,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + .fw_unplugs_cpu = pm->smi_on_cpu_unplug, + }; + build_cpus_aml(dsdt, machine, opts, pc_madt_cpu_entry, +- pm->cpu_hp_io_base, "\\_SB.PCI0", "\\_GPE._E02"); ++ pm->cpu_hp_io_base, "\\_SB.PCI0", "\\_GPE._E02", ++ AML_SYSTEM_IO); + } + + if (pcms->memhp_io_base && nr_mem) { +diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h +index f4a28df..d2ca2ee 100644 +--- a/include/hw/acpi/cpu.h ++++ b/include/hw/acpi/cpu.h +@@ -62,9 +62,10 @@ typedef void (*build_madt_cpu_fn)(int uid, const CPUArchIdList *apic_ids, + GArray *entry, bool force_enabled); + + void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, +- build_madt_cpu_fn build_madt_cpu, hwaddr io_base, ++ build_madt_cpu_fn build_madt_cpu, hwaddr base_addr, + const char *res_root, +- const char *event_handler_method); ++ const char *event_handler_method, ++ AmlRegionSpace rs); + + void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list); + +-- +1.8.3.1 + diff --git a/0258-physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch b/0258-physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch new file mode 100644 index 0000000000000000000000000000000000000000..7a76431baecb7f589e9f854c3f41fcc19cc46e17 --- /dev/null +++ b/0258-physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch @@ -0,0 +1,109 @@ +From d6ad8126f17f6fa9c7334c75c4b6a73caf40cf6b Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:15:01 +0100 +Subject: [PATCH 268/293] physmem: Add helper function to destroy CPU + AddressSpace + +Virtual CPU Hot-unplug leads to unrealization of a CPU object. This also +involves destruction of the CPU AddressSpace. Add common function to help +destroy the CPU AddressSpace. + +Signed-off-by: Salil Mehta +Tested-by: Vishnu Pajjuri +Reviewed-by: Gavin Shan +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Shaoqin Huang +Tested-by: Zhao Liu +Acked-by: Igor Mammedov +Message-Id: <20240716111502.202344-7-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + include/exec/cpu-common.h | 8 ++++++++ + include/hw/core/cpu.h | 1 + + system/physmem.c | 29 +++++++++++++++++++++++++++++ + 3 files changed, 38 insertions(+) + +diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h +index 41115d8..2a3d4aa 100644 +--- a/include/exec/cpu-common.h ++++ b/include/exec/cpu-common.h +@@ -139,6 +139,14 @@ size_t qemu_ram_pagesize_largest(void); + */ + void cpu_address_space_init(CPUState *cpu, int asidx, + const char *prefix, MemoryRegion *mr); ++/** ++ * cpu_address_space_destroy: ++ * @cpu: CPU for which address space needs to be destroyed ++ * @asidx: integer index of this address space ++ * ++ * Note that with KVM only one address space is supported. ++ */ ++void cpu_address_space_destroy(CPUState *cpu, int asidx); + + void cpu_physical_memory_rw(hwaddr addr, void *buf, + hwaddr len, bool is_write); +diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h +index c0c8320..0ae9efa 100644 +--- a/include/hw/core/cpu.h ++++ b/include/hw/core/cpu.h +@@ -496,6 +496,7 @@ struct CPUState { + QSIMPLEQ_HEAD(, qemu_work_item) work_list; + + CPUAddressSpace *cpu_ases; ++ int cpu_ases_count; + int num_ases; + AddressSpace *as; + MemoryRegion *memory; +diff --git a/system/physmem.c b/system/physmem.c +index a63853a..d74f6d4 100644 +--- a/system/physmem.c ++++ b/system/physmem.c +@@ -761,6 +761,7 @@ void cpu_address_space_init(CPUState *cpu, int asidx, + + if (!cpu->cpu_ases) { + cpu->cpu_ases = g_new0(CPUAddressSpace, cpu->num_ases); ++ cpu->cpu_ases_count = cpu->num_ases; + } + + newas = &cpu->cpu_ases[asidx]; +@@ -774,6 +775,34 @@ void cpu_address_space_init(CPUState *cpu, int asidx, + } + } + ++void cpu_address_space_destroy(CPUState *cpu, int asidx) ++{ ++ CPUAddressSpace *cpuas; ++ ++ assert(cpu->cpu_ases); ++ assert(asidx >= 0 && asidx < cpu->num_ases); ++ /* KVM cannot currently support multiple address spaces. */ ++ assert(asidx == 0 || !kvm_enabled()); ++ ++ cpuas = &cpu->cpu_ases[asidx]; ++ if (tcg_enabled()) { ++ memory_listener_unregister(&cpuas->tcg_as_listener); ++ } ++ ++ address_space_destroy(cpuas->as); ++ g_free_rcu(cpuas->as, rcu); ++ ++ if (asidx == 0) { ++ /* reset the convenience alias for address space 0 */ ++ cpu->as = NULL; ++ } ++ ++ if (--cpu->cpu_ases_count == 0) { ++ g_free(cpu->cpu_ases); ++ cpu->cpu_ases = NULL; ++ } ++} ++ + AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx) + { + /* Return the AddressSpace corresponding to the specified index */ +-- +1.8.3.1 + diff --git a/0259-gdbstub-Add-helper-function-to-unregister-GDB-regist.patch b/0259-gdbstub-Add-helper-function-to-unregister-GDB-regist.patch new file mode 100644 index 0000000000000000000000000000000000000000..90e68b5e9e9f94c0cfb8fbbb3e317b80e320ea8b --- /dev/null +++ b/0259-gdbstub-Add-helper-function-to-unregister-GDB-regist.patch @@ -0,0 +1,92 @@ +From c481143b781b61e56dd0f14e61f9d0ed14baf07a Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:15:02 +0100 +Subject: [PATCH 269/293] gdbstub: Add helper function to unregister GDB + register space + +Add common function to help unregister the GDB register space. This shall be +done in context to the CPU unrealization. + +Note: These are common functions exported to arch specific code. For example, +for ARM this code is being referred in associated arch specific patch-set: + +Link: https://lore.kernel.org/qemu-devel/20230926103654.34424-1-salil.mehta@huawei.com/ + +Signed-off-by: Salil Mehta +Tested-by: Vishnu Pajjuri +Reviewed-by: Gavin Shan +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Shaoqin Huang +Reviewed-by: Vishnu Pajjuri +Tested-by: Zhao Liu +Acked-by: Igor Mammedov +Message-Id: <20240716111502.202344-8-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + gdbstub/gdbstub.c | 13 +++++++++++++ + hw/core/cpu-common.c | 4 ++++ + include/exec/gdbstub.h | 6 ++++++ + 3 files changed, 23 insertions(+) + +diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c +index 46d752b..31c3dae 100644 +--- a/gdbstub/gdbstub.c ++++ b/gdbstub/gdbstub.c +@@ -582,6 +582,19 @@ void gdb_register_coprocessor(CPUState *cpu, + } + } + ++void gdb_unregister_coprocessor_all(CPUState *cpu) ++{ ++ /* ++ * Safe to nuke everything. GDBRegisterState::xml is static const char so ++ * it won't be freed ++ */ ++ g_array_free(cpu->gdb_regs, true); ++ ++ cpu->gdb_regs = NULL; ++ cpu->gdb_num_regs = 0; ++ cpu->gdb_num_g_regs = 0; ++} ++ + static void gdb_process_breakpoint_remove_all(GDBProcess *p) + { + CPUState *cpu = gdb_get_first_cpu_in_process(p); +diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c +index 82dae51..e36ca2c 100644 +--- a/hw/core/cpu-common.c ++++ b/hw/core/cpu-common.c +@@ -262,6 +262,10 @@ static void cpu_common_finalize(Object *obj) + { + CPUState *cpu = CPU(obj); + ++ /* If cleanup didn't happen in context to gdb_unregister_coprocessor_all */ ++ if (cpu->gdb_regs) { ++ g_array_free(cpu->gdb_regs, TRUE); ++ } + qemu_lockcnt_destroy(&cpu->in_ioctl_lock); + qemu_mutex_destroy(&cpu->work_mutex); + } +diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h +index d8a3c56..e2e8dff 100644 +--- a/include/exec/gdbstub.h ++++ b/include/exec/gdbstub.h +@@ -41,6 +41,12 @@ void gdb_register_coprocessor(CPUState *cpu, + int num_regs, const char *xml, int g_pos); + + /** ++ * gdb_unregister_coprocessor_all() - unregisters supplemental set of registers ++ * @cpu - the CPU associated with registers ++ */ ++void gdb_unregister_coprocessor_all(CPUState *cpu); ++ ++/** + * gdbserver_start: start the gdb server + * @port_or_device: connection spec for gdb + * +-- +1.8.3.1 + diff --git a/0260-accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch b/0260-accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch new file mode 100644 index 0000000000000000000000000000000000000000..ee61b17f65ab362829df94514cc0e510514157c4 --- /dev/null +++ b/0260-accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch @@ -0,0 +1,46 @@ +From 1630c693b5fbf399374bcdd606195d125f5331cd Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Thu, 1 Aug 2024 10:15:03 +0100 +Subject: [PATCH 270/293] accel/kvm/kvm-all: Fixes the missing break in vCPU + unpark logic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Loop should exit prematurely on successfully finding out the parked vCPU (struct +KVMParkedVcpu) in the 'struct KVMState' maintained 'kvm_parked_vcpus' list of +parked vCPUs. + +Fixes: Coverity CID 1558552 +Fixes: 08c3286822 ("accel/kvm: Extract common KVM vCPU {creation,parking} code") +Reported-by: Peter Maydell +Signed-off-by: Salil Mehta +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Gavin Shan +Reviewed-by: Zhao Liu +Reviewed-by: Igor Mammedov +Message-id: 20240725145132.99355-1-salil.mehta@huawei.com +Suggested-by: Peter Maydell +Message-ID: +Signed-off-by: Salil Mehta +Signed-off-by: Peter Maydell +Signed-off-by: Xianglai Li +--- + accel/kvm/kvm-all.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 169d828..6db6085 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -347,6 +347,7 @@ int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id) + QLIST_REMOVE(cpu, node); + kvm_fd = cpu->kvm_fd; + g_free(cpu); ++ break; + } + } + +-- +1.8.3.1 + diff --git a/0261-hw-loongarch-virt-Add-CPU-topology-support.patch b/0261-hw-loongarch-virt-Add-CPU-topology-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..91768971c2aebc6749c48981fc8410990be1829e --- /dev/null +++ b/0261-hw-loongarch-virt-Add-CPU-topology-support.patch @@ -0,0 +1,277 @@ +From 0b5fe1586fc3c26f15d75e9a69d68e04f07ecd92 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Sat, 26 Oct 2024 15:12:35 +0800 +Subject: [PATCH 271/293] hw/loongarch/virt: Add CPU topology support + +Add topological relationships for Loongarch VCPU and initialize +topology member variables. Also physical cpu id calculation +method comes from its topo information. + +Co-developed-by: Xianglai Li +Signed-off-by: Bibo Mao +Signed-off-by: Xianglai Li +--- + docs/system/loongarch/virt.rst | 31 ++++++++++++++++ + hw/loongarch/virt.c | 82 ++++++++++++++++++++++++++++++++++-------- + target/loongarch/cpu.c | 12 +++++++ + target/loongarch/cpu.h | 11 ++++++ + 4 files changed, 122 insertions(+), 14 deletions(-) + +diff --git a/docs/system/loongarch/virt.rst b/docs/system/loongarch/virt.rst +index c37268b..aa4719d 100644 +--- a/docs/system/loongarch/virt.rst ++++ b/docs/system/loongarch/virt.rst +@@ -28,6 +28,37 @@ The ``qemu-system-loongarch64`` provides emulation for virt + machine. You can specify the machine type ``virt`` and + cpu type ``la464``. + ++CPU Topology ++------------ ++ ++The ``LA464`` type CPUs have the concept of Socket Core and Thread. ++ ++For example: ++ ++``-smp 1,maxcpus=M,sockets=S,cores=C,threads=T`` ++ ++The above parameters indicate that the machine has a maximum of ``M`` vCPUs and ++``S`` sockets, each socket has ``C`` cores, each core has ``T`` threads, ++and each thread corresponds to a vCPU. ++ ++Then ``M`` ``S`` ``C`` ``T`` has the following relationship: ++ ++``M = S * C * T`` ++ ++In the CPU topology relationship, When we know the ``socket_id`` ``core_id`` ++and ``thread_id`` of the CPU, we can calculate its ``arch_id``: ++ ++``arch_id = (socket_id * S) + (core_id * C) + (thread_id * T)`` ++ ++Similarly, when we know the ``arch_id`` of the CPU, ++we can also get its ``socket_id`` ``core_id`` and ``thread_id``: ++ ++``socket_id = arch_id / (C * T)`` ++ ++``core_id = (arch_id / T) % C`` ++ ++``thread_id = arch_id % T`` ++ + Boot options + ------------ + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 0866022..3b298c2 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -1143,9 +1143,7 @@ static void virt_init(MachineState *machine) + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + int i; + hwaddr base, size, ram_size = machine->ram_size; +- const CPUArchIdList *possible_cpus; + MachineClass *mc = MACHINE_GET_CLASS(machine); +- CPUState *cpu; + + if (!cpu_model) { + cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); +@@ -1163,14 +1161,39 @@ static void virt_init(MachineState *machine) + memory_region_add_subregion(&lvms->system_iocsr, 0, &lvms->iocsr_mem); + + /* Init CPUs */ +- possible_cpus = mc->possible_cpu_arch_ids(machine); +- for (i = 0; i < possible_cpus->len; i++) { +- cpu = cpu_create(machine->cpu_type); +- cpu->cpu_index = i; +- machine->possible_cpus->cpus[i].cpu = OBJECT(cpu); +- lacpu = LOONGARCH_CPU(cpu); ++ mc->possible_cpu_arch_ids(machine); ++ for (i = 0; i < machine->smp.cpus; i++) { ++ Object *cpuobj; ++ cpuobj = object_new(machine->cpu_type); ++ lacpu = LOONGARCH_CPU(cpuobj); ++ + lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id; ++ object_property_set_int(cpuobj, "socket-id", ++ machine->possible_cpus->cpus[i].props.socket_id, ++ NULL); ++ object_property_set_int(cpuobj, "core-id", ++ machine->possible_cpus->cpus[i].props.core_id, ++ NULL); ++ object_property_set_int(cpuobj, "thread-id", ++ machine->possible_cpus->cpus[i].props.thread_id, ++ NULL); ++ /* ++ * The CPU in place at the time of machine startup will also enter ++ * the CPU hot-plug process when it is created, but at this time, ++ * the GED device has not been created, resulting in exit in the CPU ++ * hot-plug process, which can avoid the incumbent CPU repeatedly ++ * applying for resources. ++ * ++ * The interrupt resource of the in-place CPU will be requested at ++ * the current function call loongarch_irq_init(). ++ * ++ * The interrupt resource of the subsequently inserted CPU will be ++ * requested in the CPU hot-plug process. ++ */ ++ qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); ++ object_unref(cpuobj); + } ++ + fdt_add_cpu_nodes(lvms); + fdt_add_memory_nodes(machine); + fw_cfg_add_memory(machine); +@@ -1286,6 +1309,27 @@ static void virt_initfn(Object *obj) + virt_flash_create(lvms); + } + ++static int virt_get_arch_id_from_topo(MachineState *ms, LoongArchCPUTopo *topo) ++{ ++ int arch_id, sock_vcpu_num, core_vcpu_num; ++ ++ /* ++ * calculate total logical cpus across socket/core/thread. ++ * For more information on how to calculate the arch_id, ++ * you can refer to the CPU Topology chapter of the ++ * docs/system/loongarch/virt.rst document. ++ */ ++ sock_vcpu_num = topo->socket_id * (ms->smp.threads * ms->smp.cores); ++ core_vcpu_num = topo->core_id * ms->smp.threads; ++ ++ /* get vcpu-id(logical cpu index) for this vcpu from this topology */ ++ arch_id = (sock_vcpu_num + core_vcpu_num) + topo->thread_id; ++ ++ assert(arch_id >= 0 && arch_id < ms->possible_cpus->len); ++ ++ return arch_id; ++} ++ + static bool memhp_type_supported(DeviceState *dev) + { + /* we only support pc dimm now */ +@@ -1383,10 +1427,19 @@ static HotplugHandler *virt_get_hotplug_handler(MachineState *machine, + return NULL; + } + ++static void virt_get_cpu_topo_from_index(MachineState *ms, ++ LoongArchCPUTopo *topo, int index) ++{ ++ topo->socket_id = index / (ms->smp.cores * ms->smp.threads); ++ topo->core_id = index / ms->smp.threads % ms->smp.cores; ++ topo->thread_id = index % ms->smp.threads; ++} ++ + static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + { + int n; + unsigned int max_cpus = ms->smp.max_cpus; ++ LoongArchCPUTopo topo; + + if (ms->possible_cpus) { + assert(ms->possible_cpus->len == max_cpus); +@@ -1397,17 +1450,18 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + sizeof(CPUArchId) * max_cpus); + ms->possible_cpus->len = max_cpus; + for (n = 0; n < ms->possible_cpus->len; n++) { ++ ms->possible_cpus->cpus[n].vcpus_count = ms->smp.threads; + ms->possible_cpus->cpus[n].type = ms->cpu_type; +- ms->possible_cpus->cpus[n].arch_id = n; ++ virt_get_cpu_topo_from_index(ms, &topo, n); + + ms->possible_cpus->cpus[n].props.has_socket_id = true; +- ms->possible_cpus->cpus[n].props.socket_id = +- n / (ms->smp.cores * ms->smp.threads); ++ ms->possible_cpus->cpus[n].props.socket_id = topo.socket_id; + ms->possible_cpus->cpus[n].props.has_core_id = true; +- ms->possible_cpus->cpus[n].props.core_id = +- n / ms->smp.threads % ms->smp.cores; ++ ms->possible_cpus->cpus[n].props.core_id = topo.core_id; + ms->possible_cpus->cpus[n].props.has_thread_id = true; +- ms->possible_cpus->cpus[n].props.thread_id = n % ms->smp.threads; ++ ms->possible_cpus->cpus[n].props.thread_id = topo.thread_id; ++ ms->possible_cpus->cpus[n].arch_id = ++ virt_get_arch_id_from_topo(ms, &topo); + } + return ms->possible_cpus; + } +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 130b0c7..b85a48b 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -16,6 +16,7 @@ + #include "kvm/kvm_loongarch.h" + #include "exec/exec-all.h" + #include "cpu.h" ++#include "hw/qdev-properties.h" + #include "internals.h" + #include "fpu/softfloat-helpers.h" + #include "cpu-csr.h" +@@ -839,6 +840,15 @@ static int64_t loongarch_cpu_get_arch_id(CPUState *cs) + } + #endif + ++static Property loongarch_cpu_properties[] = { ++ DEFINE_PROP_INT32("socket-id", LoongArchCPU, socket_id, 0), ++ DEFINE_PROP_INT32("core-id", LoongArchCPU, core_id, 0), ++ DEFINE_PROP_INT32("thread-id", LoongArchCPU, thread_id, 0), ++ DEFINE_PROP_INT32("node-id", LoongArchCPU, node_id, CPU_UNSET_NUMA_NODE_ID), ++ ++ DEFINE_PROP_END_OF_LIST() ++}; ++ + static void loongarch_cpu_class_init(ObjectClass *c, void *data) + { + LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c); +@@ -846,6 +856,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) + DeviceClass *dc = DEVICE_CLASS(c); + ResettableClass *rc = RESETTABLE_CLASS(c); + ++ device_class_set_props(dc, loongarch_cpu_properties); + device_class_set_parent_realize(dc, loongarch_cpu_realizefn, + &lacc->parent_realize); + resettable_class_set_parent_phases(rc, NULL, loongarch_cpu_reset_hold, NULL, +@@ -869,6 +880,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) + #ifdef CONFIG_TCG + cc->tcg_ops = &loongarch_tcg_ops; + #endif ++ dc->user_creatable = true; + } + + static const gchar *loongarch32_gdb_arch_name(CPUState *cs) +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index d922fe3..4a3ae6f 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -388,6 +388,12 @@ typedef struct CPUArchState { + #endif + } CPULoongArchState; + ++typedef struct LoongArchCPUTopo { ++ int32_t socket_id; /* socket-id of this VCPU */ ++ int32_t core_id; /* core-id of this VCPU */ ++ int32_t thread_id; /* thread-id of this VCPU */ ++} LoongArchCPUTopo; ++ + /** + * LoongArchCPU: + * @env: #CPULoongArchState +@@ -400,6 +406,10 @@ struct ArchCPU { + CPULoongArchState env; + QEMUTimer timer; + uint32_t phy_id; ++ int32_t socket_id; /* socket-id of this VCPU */ ++ int32_t core_id; /* core-id of this VCPU */ ++ int32_t thread_id; /* thread-id of this VCPU */ ++ int32_t node_id; /* NUMA node this CPU belongs to */ + OnOffAuto lbt; + OnOffAuto pmu; + +@@ -420,6 +430,7 @@ struct LoongArchCPUClass { + CPUClass parent_class; + + DeviceRealize parent_realize; ++ DeviceUnrealize parent_unrealize; + ResettablePhases parent_phases; + }; + +-- +1.8.3.1 + diff --git a/0262-Add-basic-CPU-plug-support.patch b/0262-Add-basic-CPU-plug-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..9d130d7a1a89209526b77fb78534e56bff1539c8 --- /dev/null +++ b/0262-Add-basic-CPU-plug-support.patch @@ -0,0 +1,344 @@ +From bef4a8598a5f345267e492d43a41912676ebd5d7 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Sat, 26 Oct 2024 15:13:59 +0800 +Subject: [PATCH 272/293] Add basic CPU plug support + +Implement interface for cpu hotplug function, and enable cpu hotplug +feature on virt machine. + +Co-developed-by: Xianglai Li +Signed-off-by: Bibo Mao +Signed-off-by: Xianglai Li +--- + hw/loongarch/Kconfig | 1 + + hw/loongarch/virt.c | 191 +++++++++++++++++++++++++++++++++++++++++++- + include/hw/loongarch/virt.h | 2 + + target/loongarch/cpu.c | 13 +++ + 4 files changed, 205 insertions(+), 2 deletions(-) + +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index 9fa8f82..bf3ad0c 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -14,6 +14,7 @@ config LOONGARCH_VIRT + select LOONGARCH_EXTIOI + select LS7A_RTC + select SMBIOS ++ select ACPI_CPU_HOTPLUG + select ACPI_PCI + select ACPI_HW_REDUCED + select FW_CFG_DMA +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 3b298c2..777c1c7 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -841,7 +841,7 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + + /* Create IPI device */ + ipi = qdev_new(TYPE_LOONGARCH_IPI); +- qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.cpus); ++ qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); + + /* IPI iocsr memory region */ +@@ -865,9 +865,11 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + env->ipistate = ipi; + } + ++ lvms->ipi = ipi; ++ + /* Create EXTIOI device */ + extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); +- qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus); ++ qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.max_cpus); + if (virt_is_veiointc_enabled(lvms)) { + qdev_prop_set_bit(extioi, "has-virtualization-extension", true); + } +@@ -891,6 +893,8 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + } + } + ++ lvms->extioi = extioi; ++ + /* Add Extend I/O Interrupt Controller node */ + fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle); + +@@ -1330,6 +1334,179 @@ static int virt_get_arch_id_from_topo(MachineState *ms, LoongArchCPUTopo *topo) + return arch_id; + } + ++/* find cpu slot in machine->possible_cpus by arch_id */ ++static CPUArchId *virt_find_cpu_slot(MachineState *ms, int arch_id, int *index) ++{ ++ int n; ++ for (n = 0; n < ms->possible_cpus->len; n++) { ++ if (ms->possible_cpus->cpus[n].arch_id == arch_id) { ++ if (index) { ++ *index = n; ++ } ++ return &ms->possible_cpus->cpus[n]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ MachineState *ms = MACHINE(OBJECT(hotplug_dev)); ++ MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); ++ LoongArchCPU *cpu = LOONGARCH_CPU(dev); ++ CPUState *cs = CPU(dev); ++ CPUArchId *cpu_slot; ++ Error *local_err = NULL; ++ LoongArchCPUTopo topo; ++ int arch_id, index; ++ ++ if (dev->hotplugged && !mc->has_hotpluggable_cpus) { ++ error_setg(&local_err, "CPU hotplug not supported for this machine"); ++ goto out; ++ } ++ ++ /* sanity check the cpu */ ++ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { ++ error_setg(&local_err, "Invalid CPU type, expected cpu type: '%s'", ++ ms->cpu_type); ++ goto out; ++ } ++ ++ if ((cpu->thread_id < 0) || (cpu->thread_id >= ms->smp.threads)) { ++ error_setg(&local_err, ++ "Invalid thread-id %u specified, must be in range 1:%u", ++ cpu->thread_id, ms->smp.threads - 1); ++ goto out; ++ } ++ ++ if ((cpu->core_id < 0) || (cpu->core_id >= ms->smp.cores)) { ++ error_setg(&local_err, ++ "Invalid core-id %u specified, must be in range 1:%u", ++ cpu->core_id, ms->smp.cores - 1); ++ goto out; ++ } ++ ++ if ((cpu->socket_id < 0) || (cpu->socket_id >= ms->smp.sockets)) { ++ error_setg(&local_err, ++ "Invalid socket-id %u specified, must be in range 1:%u", ++ cpu->socket_id, ms->smp.sockets - 1); ++ goto out; ++ } ++ ++ topo.socket_id = cpu->socket_id; ++ topo.core_id = cpu->core_id; ++ topo.thread_id = cpu->thread_id; ++ arch_id = virt_get_arch_id_from_topo(ms, &topo); ++ cpu_slot = virt_find_cpu_slot(ms, arch_id, &index); ++ if (CPU(cpu_slot->cpu)) { ++ error_setg(&local_err, ++ "cpu(id%d=%d:%d:%d) with arch-id %" PRIu64 " exists", ++ cs->cpu_index, cpu->socket_id, cpu->core_id, ++ cpu->thread_id, cpu_slot->arch_id); ++ goto out; ++ } ++ cpu->phy_id = arch_id; ++ /* ++ * update cpu_index calculation method since it is easily used as index ++ * with possible_cpus array by function virt_cpu_index_to_props ++ */ ++ cs->cpu_index = index; ++ numa_cpu_pre_plug(cpu_slot, dev, &local_err); ++ return ; ++ ++out: ++ error_propagate(errp, local_err); ++} ++ ++static void virt_cpu_unplug_request(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ Error *local_err = NULL; ++ HotplugHandlerClass *hhc; ++ LoongArchCPU *cpu = LOONGARCH_CPU(dev); ++ CPUState *cs = CPU(dev); ++ ++ if (!lvms->acpi_ged) { ++ error_setg(&local_err, "CPU hot unplug not supported without ACPI"); ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ if (cs->cpu_index == 0) { ++ error_setg(&local_err, ++ "hot-unplug of boot cpu(id%d=%d:%d:%d) not supported", ++ cs->cpu_index, cpu->socket_id, ++ cpu->core_id, cpu->thread_id); ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lvms->acpi_ged); ++ hhc->unplug_request(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &local_err); ++} ++ ++static void virt_cpu_unplug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ CPUArchId *cpu_slot; ++ HotplugHandlerClass *hhc; ++ Error *local_err = NULL; ++ LoongArchCPU *cpu = LOONGARCH_CPU(dev); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lvms->acpi_ged); ++ hhc->unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id, NULL); ++ cpu_slot->cpu = NULL; ++ return; ++} ++ ++static void virt_cpu_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ CPUArchId *cpu_slot; ++ HotplugHandlerClass *hhc; ++ Error *local_err = NULL; ++ LoongArchCPU *cpu = LOONGARCH_CPU(dev); ++ CPUState *cs = CPU(cpu); ++ CPULoongArchState *env; ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ int pin; ++ ++ if (lvms->acpi_ged) { ++ env = &(cpu->env); ++ env->address_space_iocsr = &lvms->as_iocsr; ++ ++ /* connect ipi irq to cpu irq, logic cpu index used here */ ++ qdev_connect_gpio_out(lvms->ipi, cs->cpu_index, ++ qdev_get_gpio_in(dev, IRQ_IPI)); ++ env->ipistate = lvms->ipi; ++ ++ for (pin = 0; pin < LS3A_INTC_IP; pin++) { ++ qdev_connect_gpio_out(lvms->extioi, (cs->cpu_index * 8 + pin), ++ qdev_get_gpio_in(dev, pin + 2)); ++ } ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lvms->acpi_ged); ++ hhc->plug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ } ++ ++ cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id, NULL); ++ cpu_slot->cpu = OBJECT(dev); ++ return; ++} ++ + static bool memhp_type_supported(DeviceState *dev) + { + /* we only support pc dimm now */ +@@ -1348,6 +1525,8 @@ static void virt_device_pre_plug(HotplugHandler *hotplug_dev, + { + if (memhp_type_supported(dev)) { + virt_mem_pre_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ virt_cpu_pre_plug(hotplug_dev, dev, errp); + } + } + +@@ -1366,6 +1545,8 @@ static void virt_device_unplug_request(HotplugHandler *hotplug_dev, + { + if (memhp_type_supported(dev)) { + virt_mem_unplug_request(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ virt_cpu_unplug_request(hotplug_dev, dev, errp); + } + } + +@@ -1384,6 +1565,8 @@ static void virt_device_unplug(HotplugHandler *hotplug_dev, + { + if (memhp_type_supported(dev)) { + virt_mem_unplug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ virt_cpu_unplug(hotplug_dev, dev, errp); + } + } + +@@ -1411,6 +1594,8 @@ static void virt_device_plug_cb(HotplugHandler *hotplug_dev, + } + } else if (memhp_type_supported(dev)) { + virt_mem_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ virt_cpu_plug(hotplug_dev, dev, errp); + } + } + +@@ -1420,6 +1605,7 @@ static HotplugHandler *virt_get_hotplug_handler(MachineState *machine, + MachineClass *mc = MACHINE_GET_CLASS(machine); + + if (device_is_dynamic_sysbus(mc, dev) || ++ object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU) || + object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) || + memhp_type_supported(dev)) { + return HOTPLUG_HANDLER(machine); +@@ -1508,6 +1694,7 @@ static void virt_class_init(ObjectClass *oc, void *data) + mc->numa_mem_supported = true; + mc->auto_enable_numa_with_memhp = true; + mc->auto_enable_numa_with_memdev = true; ++ mc->has_hotpluggable_cpus = true; + mc->get_hotplug_handler = virt_get_hotplug_handler; + mc->default_nic = "virtio-net-pci"; + hc->plug = virt_device_plug_cb; +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index c373e48..773e43b 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -61,6 +61,8 @@ struct LoongArchVirtMachineState { + MemoryRegion iocsr_mem; + AddressSpace as_iocsr; + struct loongarch_boot_info bootinfo; ++ DeviceState *ipi; ++ DeviceState *extioi; + }; + + #define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index b85a48b..78f4a95 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -623,6 +623,17 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) + lacc->parent_realize(dev, errp); + } + ++static void loongarch_cpu_unrealizefn(DeviceState *dev) ++{ ++ LoongArchCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(dev); ++ ++#ifndef CONFIG_USER_ONLY ++ cpu_remove_sync(CPU(dev)); ++#endif ++ ++ mcc->parent_unrealize(dev); ++} ++ + static bool loongarch_get_lsx(Object *obj, Error **errp) + { + LoongArchCPU *cpu = LOONGARCH_CPU(obj); +@@ -859,6 +870,8 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) + device_class_set_props(dc, loongarch_cpu_properties); + device_class_set_parent_realize(dc, loongarch_cpu_realizefn, + &lacc->parent_realize); ++ device_class_set_parent_unrealize(dc, loongarch_cpu_unrealizefn, ++ &lacc->parent_unrealize); + resettable_class_set_parent_phases(rc, NULL, loongarch_cpu_reset_hold, NULL, + &lacc->parent_phases); + +-- +1.8.3.1 + diff --git a/0263-hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch b/0263-hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a80e68459a09452f3cfb61fa9b4be47d3129a4c --- /dev/null +++ b/0263-hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch @@ -0,0 +1,142 @@ +From c28dc32ab267b439eb48c8903005ffb71eac53e8 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Sat, 26 Oct 2024 15:15:22 +0800 +Subject: [PATCH 273/293] hw/loongarch/virt: Update the ACPI table for hotplug + cpu + +On LoongArch virt machine, ACPI GED hardware is used for cpu +hotplug, here cpu hotplug support feature is added on GED device, +also cpu scan and reject method is added about CPU device in +DSDT table. + +Co-developed-by: Xianglai Li +Signed-off-by: Bibo Mao +Signed-off-by: Xianglai Li +--- + hw/loongarch/acpi-build.c | 35 +++++++++++++++++++++++++++++++++-- + hw/loongarch/virt.c | 10 ++++++++++ + include/hw/loongarch/virt.h | 1 + + 3 files changed, 44 insertions(+), 2 deletions(-) + +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +index a41e4c2..c291cf6 100644 +--- a/hw/loongarch/acpi-build.c ++++ b/hw/loongarch/acpi-build.c +@@ -47,6 +47,22 @@ + #define ACPI_BUILD_DPRINTF(fmt, ...) + #endif + ++static void virt_madt_cpu_entry(int uid, ++ const CPUArchIdList *apic_ids, ++ GArray *entry, bool force_enabled) ++{ ++ uint32_t flags, apic_id = apic_ids->cpus[uid].arch_id; ++ ++ flags = apic_ids->cpus[uid].cpu || force_enabled ? 1 /* Enabled */ : 0; ++ ++ /* Rev 1.0b, Table 5-13 Processor Local APIC Structure */ ++ build_append_int_noprefix(entry, 0, 1); /* Type */ ++ build_append_int_noprefix(entry, 8, 1); /* Length */ ++ build_append_int_noprefix(entry, uid, 1); /* ACPI Processor ID */ ++ build_append_int_noprefix(entry, apic_id, 1); /* APIC ID */ ++ build_append_int_noprefix(entry, flags, 4); /* Flags */ ++} ++ + /* build FADT */ + static void init_common_fadt_data(AcpiFadtData *data) + { +@@ -123,15 +139,17 @@ build_madt(GArray *table_data, BIOSLinker *linker, + build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ + + for (i = 0; i < arch_ids->len; i++) { ++ uint32_t flags; ++ + /* Processor Core Interrupt Controller Structure */ + arch_id = arch_ids->cpus[i].arch_id; +- ++ flags = arch_ids->cpus[i].cpu ? 1 : 0; + build_append_int_noprefix(table_data, 17, 1); /* Type */ + build_append_int_noprefix(table_data, 15, 1); /* Length */ + build_append_int_noprefix(table_data, 1, 1); /* Version */ + build_append_int_noprefix(table_data, i, 4); /* ACPI Processor ID */ + build_append_int_noprefix(table_data, arch_id, 4); /* Core ID */ +- build_append_int_noprefix(table_data, 1, 4); /* Flags */ ++ build_append_int_noprefix(table_data, flags, 4); /* Flags */ + } + + /* Extend I/O Interrupt Controller Structure */ +@@ -296,6 +314,7 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine) + { + uint32_t event; + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); ++ CPUHotplugFeatures opts; + + build_ged_aml(dsdt, "\\_SB."GED_DEVICE, + HOTPLUG_HANDLER(lvms->acpi_ged), +@@ -308,6 +327,18 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine) + AML_SYSTEM_MEMORY, + VIRT_GED_MEM_ADDR); + } ++ ++ if (event & ACPI_GED_CPU_HOTPLUG_EVT) { ++ opts.acpi_1_compatible = false; ++ opts.has_legacy_cphp = false; ++ opts.fw_unplugs_cpu = false; ++ opts.smi_path = NULL; ++ ++ build_cpus_aml(dsdt, machine, opts, virt_madt_cpu_entry, ++ VIRT_GED_CPUHP_ADDR, "\\_SB", ++ AML_GED_EVT_CPU_SCAN_METHOD, AML_SYSTEM_MEMORY); ++ } ++ + acpi_dsdt_add_power_button(dsdt); + } + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 777c1c7..4f17079 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -650,11 +650,17 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic, + { + DeviceState *dev; + MachineState *ms = MACHINE(lvms); ++ MachineClass *mc = MACHINE_GET_CLASS(lvms); + uint32_t event = ACPI_GED_PWR_DOWN_EVT; + + if (ms->ram_slots) { + event |= ACPI_GED_MEM_HOTPLUG_EVT; + } ++ ++ if (mc->has_hotpluggable_cpus) { ++ event |= ACPI_GED_CPU_HOTPLUG_EVT; ++ } ++ + dev = qdev_new(TYPE_ACPI_GED); + qdev_prop_set_uint32(dev, "ged-event", event); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); +@@ -666,6 +672,10 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic, + /* ged regs used for reset and power down */ + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_GED_REG_ADDR); + ++ if (mc->has_hotpluggable_cpus) { ++ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 3, VIRT_GED_CPUHP_ADDR); ++ } ++ + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, + qdev_get_gpio_in(pch_pic, VIRT_SCI_IRQ - VIRT_GSI_BASE)); + return dev; +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 773e43b..25abc23 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -31,6 +31,7 @@ + #define VIRT_GED_EVT_ADDR 0x100e0000 + #define VIRT_GED_MEM_ADDR (VIRT_GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN) + #define VIRT_GED_REG_ADDR (VIRT_GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN) ++#define VIRT_GED_CPUHP_ADDR (VIRT_GED_REG_ADDR + ACPI_GED_REG_COUNT) + + #define COMMAND_LINE_SIZE 512 + +-- +1.8.3.1 + diff --git a/0264-hw-loongarch-Add-KVM-IPI-device-support.patch b/0264-hw-loongarch-Add-KVM-IPI-device-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..dfd45c23d5f99e4f6f2c5acf8b3da3c915c18cbf --- /dev/null +++ b/0264-hw-loongarch-Add-KVM-IPI-device-support.patch @@ -0,0 +1,443 @@ +From a7d2b2fa658476a09027adb9c4068c03582ea59e Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Thu, 7 Mar 2024 19:38:41 +0800 +Subject: [PATCH 274/293] hw/loongarch: Add KVM IPI device support + +Added ipi interrupt controller for kvm emulation. +The main process is to send the command word for +creating an ipi device to the kernel. +When the VM is saved, the ioctl obtains the ipi +interrupt controller data in the kernel and saves it. +When the VM is recovered, the saved data is sent to the kernel. + +Signed-off-by: Tianrui Zhao +Signed-off-by: Xianglai Li +--- + hw/intc/Kconfig | 3 + + hw/intc/loongarch_ipi_kvm.c | 207 ++++++++++++++++++++++++++++++++++++++ + hw/intc/meson.build | 1 + + hw/loongarch/Kconfig | 1 + + hw/loongarch/virt.c | 49 +++++---- + include/hw/intc/loongarch_ipi.h | 22 ++++ + linux-headers/asm-loongarch/kvm.h | 3 + + linux-headers/linux/kvm.h | 2 + + target/loongarch/kvm/kvm.c | 5 + + 9 files changed, 271 insertions(+), 22 deletions(-) + create mode 100644 hw/intc/loongarch_ipi_kvm.c + +diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig +index 2b5b2d2..eddea0f 100644 +--- a/hw/intc/Kconfig ++++ b/hw/intc/Kconfig +@@ -93,6 +93,9 @@ config NIOS2_VIC + config LOONGARCH_IPI + bool + ++config LOONGARCH_IPI_KVM ++ bool ++ + config LOONGARCH_PCH_PIC + bool + select UNIMP +diff --git a/hw/intc/loongarch_ipi_kvm.c b/hw/intc/loongarch_ipi_kvm.c +new file mode 100644 +index 0000000..fd308eb +--- /dev/null ++++ b/hw/intc/loongarch_ipi_kvm.c +@@ -0,0 +1,207 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch kvm ipi interrupt support ++ * ++ * Copyright (C) 2024 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/qdev-properties.h" ++#include "qemu/typedefs.h" ++#include "hw/intc/loongarch_ipi.h" ++#include "hw/sysbus.h" ++#include "linux/kvm.h" ++#include "migration/vmstate.h" ++#include "qapi/error.h" ++#include "sysemu/kvm.h" ++ ++#define IPI_DEV_FD_UNDEF -1 ++ ++static void kvm_ipi_access_regs(int fd, uint64_t addr, ++ uint32_t *val, int is_write) ++{ ++ kvm_device_access(fd, KVM_DEV_LOONGARCH_IPI_GRP_REGS, ++ addr, val, is_write, &error_abort); ++} ++ ++static int kvm_loongarch_ipi_pre_save(void *opaque) ++{ ++ KVMLoongArchIPI *ipi = (KVMLoongArchIPI *)opaque; ++ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(ipi); ++ IPICore *cpu; ++ uint64_t attr; ++ int cpu_id = 0; ++ int fd = ipi_class->dev_fd; ++ ++ for (cpu_id = 0; cpu_id < ipi->num_cpu; cpu_id++) { ++ cpu = &ipi->cpu[cpu_id]; ++ attr = (cpu_id << 16) | CORE_STATUS_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->status, false); ++ ++ attr = (cpu_id << 16) | CORE_EN_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->en, false); ++ ++ attr = (cpu_id << 16) | CORE_SET_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->set, false); ++ ++ attr = (cpu_id << 16) | CORE_CLEAR_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->clear, false); ++ ++ attr = (cpu_id << 16) | CORE_BUF_20; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[0], false); ++ ++ attr = (cpu_id << 16) | CORE_BUF_28; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[2], false); ++ ++ attr = (cpu_id << 16) | CORE_BUF_30; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[4], false); ++ ++ attr = (cpu_id << 16) | CORE_BUF_38; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[6], false); ++ } ++ ++ return 0; ++} ++ ++static int kvm_loongarch_ipi_post_load(void *opaque, int version_id) ++{ ++ KVMLoongArchIPI *ipi = (KVMLoongArchIPI *)opaque; ++ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(ipi); ++ IPICore *cpu; ++ uint64_t attr; ++ int cpu_id = 0; ++ int fd = ipi_class->dev_fd; ++ ++ for (cpu_id = 0; cpu_id < ipi->num_cpu; cpu_id++) { ++ cpu = &ipi->cpu[cpu_id]; ++ attr = (cpu_id << 16) | CORE_STATUS_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->status, true); ++ ++ attr = (cpu_id << 16) | CORE_EN_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->en, true); ++ ++ attr = (cpu_id << 16) | CORE_SET_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->set, true); ++ ++ attr = (cpu_id << 16) | CORE_CLEAR_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->clear, true); ++ ++ attr = (cpu_id << 16) | CORE_BUF_20; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[0], true); ++ ++ attr = (cpu_id << 16) | CORE_BUF_28; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[2], true); ++ ++ attr = (cpu_id << 16) | CORE_BUF_30; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[4], true); ++ ++ attr = (cpu_id << 16) | CORE_BUF_38; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[6], true); ++ } ++ ++ return 0; ++} ++ ++static void kvm_loongarch_ipi_realize(DeviceState *dev, Error **errp) ++{ ++ KVMLoongArchIPI *ipi = KVM_LOONGARCH_IPI(dev); ++ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(dev); ++ struct kvm_create_device cd = {0}; ++ Error *err = NULL; ++ int ret; ++ ++ if (ipi->num_cpu == 0) { ++ error_setg(errp, "num-cpu must be at least 1"); ++ return; ++ } ++ ++ ipi_class->parent_realize(dev, &err); ++ if (err) { ++ error_propagate(errp, err); ++ return; ++ } ++ ++ ipi->cpu = g_new0(IPICore, ipi->num_cpu); ++ if (ipi->cpu == NULL) { ++ error_setg(errp, "Memory allocation for ExtIOICore faile"); ++ return; ++ } ++ ++ if (!ipi_class->is_created) { ++ cd.type = KVM_DEV_TYPE_LA_IPI; ++ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); ++ if (ret < 0) { ++ error_setg_errno(errp, errno, "Creating the KVM device failed"); ++ return; ++ } ++ ipi_class->is_created = true; ++ ipi_class->dev_fd = cd.fd; ++ fprintf(stdout, "Create LoongArch IPI irqchip in KVM done!\n"); ++ } ++ ++ assert(ipi_class->dev_fd != IPI_DEV_FD_UNDEF); ++} ++ ++static Property kvm_loongarch_ipi_properties[] = { ++ DEFINE_PROP_UINT32("num-cpu", KVMLoongArchIPI, num_cpu, 1), ++ DEFINE_PROP_END_OF_LIST() ++}; ++ ++static const VMStateDescription vmstate_kvm_ipi_core = { ++ .name = "kvm-ipi-single", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT32(status, IPICore), ++ VMSTATE_UINT32(en, IPICore), ++ VMSTATE_UINT32(set, IPICore), ++ VMSTATE_UINT32(clear, IPICore), ++ VMSTATE_UINT32_ARRAY(buf, IPICore, 8), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static const VMStateDescription vmstate_kvm_loongarch_ipi = { ++ .name = TYPE_KVM_LOONGARCH_IPI, ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = kvm_loongarch_ipi_pre_save, ++ .post_load = kvm_loongarch_ipi_post_load, ++ .fields = (VMStateField[]) { ++ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, KVMLoongArchIPI, num_cpu, ++ vmstate_kvm_ipi_core, IPICore), ++ ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static void kvm_loongarch_ipi_class_init(ObjectClass *oc, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(oc); ++ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_CLASS(oc); ++ ++ ipi_class->parent_realize = dc->realize; ++ dc->realize = kvm_loongarch_ipi_realize; ++ ++ ipi_class->is_created = false; ++ ipi_class->dev_fd = IPI_DEV_FD_UNDEF; ++ ++ device_class_set_props(dc, kvm_loongarch_ipi_properties); ++ ++ dc->vmsd = &vmstate_kvm_loongarch_ipi; ++} ++ ++static const TypeInfo kvm_loongarch_ipi_info = { ++ .name = TYPE_KVM_LOONGARCH_IPI, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(KVMLoongArchIPI), ++ .class_size = sizeof(KVMLoongArchIPIClass), ++ .class_init = kvm_loongarch_ipi_class_init, ++}; ++ ++static void kvm_loongarch_ipi_register_types(void) ++{ ++ type_register_static(&kvm_loongarch_ipi_info); ++} ++ ++type_init(kvm_loongarch_ipi_register_types) +diff --git a/hw/intc/meson.build b/hw/intc/meson.build +index ed35594..9deeeb5 100644 +--- a/hw/intc/meson.build ++++ b/hw/intc/meson.build +@@ -70,6 +70,7 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'], + specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) + specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) ++specific_ss.add(when: 'CONFIG_LOONGARCH_IPI_KVM', if_true: files('loongarch_ipi_kvm.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c')) +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index bf3ad0c..c6e4976 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -12,6 +12,7 @@ config LOONGARCH_VIRT + select LOONGARCH_PCH_PIC + select LOONGARCH_PCH_MSI + select LOONGARCH_EXTIOI ++ select LOONGARCH_IPI_KVM if KVM + select LS7A_RTC + select SMBIOS + select ACPI_CPU_HOTPLUG +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 4f17079..a570b0d 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -49,6 +49,7 @@ + #include "hw/virtio/virtio-iommu.h" + #include "qemu/error-report.h" + #include "qemu/guest-random.h" ++#include "sysemu/kvm.h" + + static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms) + { +@@ -849,16 +850,21 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + * +--------+ +---------+ +---------+ + */ + +- /* Create IPI device */ +- ipi = qdev_new(TYPE_LOONGARCH_IPI); +- qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus); +- sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); +- +- /* IPI iocsr memory region */ +- memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX, +- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0)); +- memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR, +- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1)); ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ ipi = qdev_new(TYPE_KVM_LOONGARCH_IPI); ++ qdev_prop_set_int32(ipi, "num-cpu", ms->smp.max_cpus); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); ++ } else { ++ ipi = qdev_new(TYPE_LOONGARCH_IPI); ++ qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); ++ ++ /* IPI iocsr memory region */ ++ memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0)); ++ memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1)); ++ } + + /* Add cpu interrupt-controller */ + fdt_add_cpuic_node(lvms, &cpuintc_phandle); +@@ -869,10 +875,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + lacpu = LOONGARCH_CPU(cpu_state); + env = &(lacpu->env); + env->address_space_iocsr = &lvms->as_iocsr; +- +- /* connect ipi irq to cpu irq */ +- qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); +- env->ipistate = ipi; + } + + lvms->ipi = ipi; +@@ -1495,15 +1497,18 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, + env = &(cpu->env); + env->address_space_iocsr = &lvms->as_iocsr; + +- /* connect ipi irq to cpu irq, logic cpu index used here */ +- qdev_connect_gpio_out(lvms->ipi, cs->cpu_index, +- qdev_get_gpio_in(dev, IRQ_IPI)); +- env->ipistate = lvms->ipi; + +- for (pin = 0; pin < LS3A_INTC_IP; pin++) { +- qdev_connect_gpio_out(lvms->extioi, (cs->cpu_index * 8 + pin), +- qdev_get_gpio_in(dev, pin + 2)); +- } ++ env->ipistate = lvms->ipi; ++ if (!(kvm_enabled() && kvm_irqchip_in_kernel())) { ++ /* connect ipi irq to cpu irq, logic cpu index used here */ ++ qdev_connect_gpio_out(lvms->ipi, cs->cpu_index, ++ qdev_get_gpio_in(dev, IRQ_IPI)); ++ ++ for (pin = 0; pin < LS3A_INTC_IP; pin++) { ++ qdev_connect_gpio_out(lvms->extioi, (cs->cpu_index * 8 + pin), ++ qdev_get_gpio_in(dev, pin + 2)); ++ } ++ } + hhc = HOTPLUG_HANDLER_GET_CLASS(lvms->acpi_ged); + hhc->plug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &local_err); + if (local_err) { +diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h +index 1c1e834..a1a4a21 100644 +--- a/include/hw/intc/loongarch_ipi.h ++++ b/include/hw/intc/loongarch_ipi.h +@@ -32,6 +32,7 @@ + + #define TYPE_LOONGARCH_IPI "loongarch_ipi" + OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI) ++#define TYPE_KVM_LOONGARCH_IPI "loongarch-ipi-kvm" + + typedef struct IPICore { + uint32_t status; +@@ -51,4 +52,25 @@ struct LoongArchIPI { + IPICore *cpu; + }; + ++struct KVMLoongArchIPI { ++ SysBusDevice parent_obj; ++ uint32_t num_cpu; ++ IPICore *cpu; ++}; ++typedef struct KVMLoongArchIPI KVMLoongArchIPI; ++DECLARE_INSTANCE_CHECKER(KVMLoongArchIPI, KVM_LOONGARCH_IPI, ++ TYPE_KVM_LOONGARCH_IPI) ++ ++struct KVMLoongArchIPIClass { ++ SysBusDeviceClass parent_class; ++ DeviceRealize parent_realize; ++ ++ bool is_created; ++ int dev_fd; ++ ++}; ++typedef struct KVMLoongArchIPIClass KVMLoongArchIPIClass; ++DECLARE_CLASS_CHECKERS(KVMLoongArchIPIClass, KVM_LOONGARCH_IPI, ++ TYPE_KVM_LOONGARCH_IPI) ++ + #endif +diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h +index d619b94..5fbf4a6 100644 +--- a/linux-headers/asm-loongarch/kvm.h ++++ b/linux-headers/asm-loongarch/kvm.h +@@ -147,4 +147,7 @@ struct kvm_iocsr_entry { + + #define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 0x40000005 + ++#define KVM_LOONGARCH_VM_HAVE_IRQCHIP 0x40000001 ++ ++#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000002 + #endif /* __UAPI_ASM_LOONGARCH_KVM_H */ +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 36da75b..dbe953d 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1464,6 +1464,8 @@ enum kvm_device_type { + #define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME + KVM_DEV_TYPE_RISCV_AIA, + #define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA ++ KVM_DEV_TYPE_LA_IPI, ++#define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI + KVM_DEV_TYPE_MAX, + }; + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index f98abf0..e2e77ab 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -962,7 +962,12 @@ int kvm_arch_get_default_type(MachineState *ms) + + int kvm_arch_init(MachineState *ms, KVMState *s) + { ++ s->kernel_irqchip_allowed = false; + cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); ++ if(!kvm_vm_check_attr(kvm_state, KVM_LOONGARCH_VM_HAVE_IRQCHIP, KVM_LOONGARCH_VM_HAVE_IRQCHIP)) { ++ s->kernel_irqchip_allowed = false; ++ } ++ + return 0; + } + +-- +1.8.3.1 + diff --git a/0265-hw-loongarch-Add-KVM-extioi-device-support.patch b/0265-hw-loongarch-Add-KVM-extioi-device-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..4ca1ec5e85c460869737b791dc2bb32d54775ef2 --- /dev/null +++ b/0265-hw-loongarch-Add-KVM-extioi-device-support.patch @@ -0,0 +1,393 @@ +From bda408a1dafde7261253f184d39d993a14327c73 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Thu, 11 Jul 2024 20:11:31 +0800 +Subject: [PATCH 275/293] hw/loongarch: Add KVM extioi device support + +Added extioi interrupt controller for kvm emulation. +The main process is to send the command word for +creating an extioi device to the kernel. +When the VM is saved, the ioctl obtains the related +data of the extioi interrupt controller in the kernel +and saves it. When the VM is recovered, the saved data +is sent to the kernel. + +Signed-off-by: Tianrui Zhao +Signed-off-by: Xianglai Li +--- + hw/intc/Kconfig | 3 + + hw/intc/loongarch_extioi_kvm.c | 150 +++++++++++++++++++++++++++++++++++++ + hw/intc/meson.build | 1 + + hw/loongarch/Kconfig | 1 + + hw/loongarch/virt.c | 48 ++++++------ + include/hw/intc/loongarch_extioi.h | 34 ++++++++- + include/hw/loongarch/virt.h | 15 ++++ + linux-headers/asm-loongarch/kvm.h | 3 + + linux-headers/linux/kvm.h | 2 + + 9 files changed, 233 insertions(+), 24 deletions(-) + create mode 100644 hw/intc/loongarch_extioi_kvm.c + +diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig +index eddea0f..3bf0c82 100644 +--- a/hw/intc/Kconfig ++++ b/hw/intc/Kconfig +@@ -107,3 +107,6 @@ config LOONGARCH_PCH_MSI + + config LOONGARCH_EXTIOI + bool ++ ++config LOONGARCH_EXTIOI_KVM ++ bool +diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c +new file mode 100644 +index 0000000..f5bbc33 +--- /dev/null ++++ b/hw/intc/loongarch_extioi_kvm.c +@@ -0,0 +1,150 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch kvm extioi interrupt support ++ * ++ * Copyright (C) 2024 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/qdev-properties.h" ++#include "qemu/typedefs.h" ++#include "hw/intc/loongarch_extioi.h" ++#include "hw/sysbus.h" ++#include "linux/kvm.h" ++#include "migration/vmstate.h" ++#include "qapi/error.h" ++#include "sysemu/kvm.h" ++ ++static void kvm_extioi_access_regs(int fd, uint64_t addr, ++ void *val, int is_write) ++{ ++ kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS, ++ addr, val, is_write, &error_abort); ++} ++ ++static int kvm_loongarch_extioi_pre_save(void *opaque) ++{ ++ KVMLoongArchExtIOI *s = (KVMLoongArchExtIOI *)opaque; ++ KVMLoongArchExtIOIClass *class = KVM_LOONGARCH_EXTIOI_GET_CLASS(s); ++ int fd = class->dev_fd; ++ ++ kvm_extioi_access_regs(fd, EXTIOI_NODETYPE_START, ++ (void *)s->nodetype, false); ++ kvm_extioi_access_regs(fd, EXTIOI_IPMAP_START, (void *)s->ipmap, false); ++ kvm_extioi_access_regs(fd, EXTIOI_ENABLE_START, (void *)s->enable, false); ++ kvm_extioi_access_regs(fd, EXTIOI_BOUNCE_START, (void *)s->bounce, false); ++ kvm_extioi_access_regs(fd, EXTIOI_ISR_START, (void *)s->isr, false); ++ kvm_extioi_access_regs(fd, EXTIOI_COREMAP_START, ++ (void *)s->coremap, false); ++ kvm_extioi_access_regs(fd, EXTIOI_SW_COREMAP_FLAG, ++ (void *)s->sw_coremap, false); ++ kvm_extioi_access_regs(fd, EXTIOI_COREISR_START, ++ (void *)s->coreisr, false); ++ ++ return 0; ++} ++ ++static int kvm_loongarch_extioi_post_load(void *opaque, int version_id) ++{ ++ KVMLoongArchExtIOI *s = (KVMLoongArchExtIOI *)opaque; ++ KVMLoongArchExtIOIClass *class = KVM_LOONGARCH_EXTIOI_GET_CLASS(s); ++ int fd = class->dev_fd; ++ ++ kvm_extioi_access_regs(fd, EXTIOI_NODETYPE_START, ++ (void *)s->nodetype, true); ++ kvm_extioi_access_regs(fd, EXTIOI_IPMAP_START, (void *)s->ipmap, true); ++ kvm_extioi_access_regs(fd, EXTIOI_ENABLE_START, (void *)s->enable, true); ++ kvm_extioi_access_regs(fd, EXTIOI_BOUNCE_START, (void *)s->bounce, true); ++ kvm_extioi_access_regs(fd, EXTIOI_ISR_START, (void *)s->isr, true); ++ kvm_extioi_access_regs(fd, EXTIOI_COREMAP_START, (void *)s->coremap, true); ++ kvm_extioi_access_regs(fd, EXTIOI_SW_COREMAP_FLAG, ++ (void *)s->sw_coremap, true); ++ kvm_extioi_access_regs(fd, EXTIOI_COREISR_START, (void *)s->coreisr, true); ++ ++ return 0; ++} ++ ++static void kvm_loongarch_extioi_realize(DeviceState *dev, Error **errp) ++{ ++ KVMLoongArchExtIOIClass *extioi_class = KVM_LOONGARCH_EXTIOI_GET_CLASS(dev); ++ struct kvm_create_device cd = {0}; ++ Error *err = NULL; ++ int ret,i; ++ ++ extioi_class->parent_realize(dev, &err); ++ if (err) { ++ error_propagate(errp, err); ++ return; ++ } ++ ++ if (!extioi_class->is_created) { ++ cd.type = KVM_DEV_TYPE_LA_EXTIOI; ++ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); ++ if (ret < 0) { ++ error_setg_errno(errp, errno, ++ "Creating the KVM extioi device failed"); ++ return; ++ } ++ extioi_class->is_created = true; ++ extioi_class->dev_fd = cd.fd; ++ fprintf(stdout, "Create LoongArch extioi irqchip in KVM done!\n"); ++ } ++ ++ kvm_async_interrupts_allowed = true; ++ kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); ++ if (kvm_has_gsi_routing()) { ++ for (i = 0; i < 64; ++i) { ++ kvm_irqchip_add_irq_route(kvm_state, i, 0, i); ++ } ++ kvm_gsi_routing_allowed = true; ++ } ++} ++ ++static const VMStateDescription vmstate_kvm_extioi_core = { ++ .name = "kvm-extioi-single", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = kvm_loongarch_extioi_pre_save, ++ .post_load = kvm_loongarch_extioi_post_load, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT32_ARRAY(nodetype, KVMLoongArchExtIOI, ++ EXTIOI_IRQS_NODETYPE_COUNT / 2), ++ VMSTATE_UINT32_ARRAY(bounce, KVMLoongArchExtIOI, ++ EXTIOI_IRQS_GROUP_COUNT), ++ VMSTATE_UINT32_ARRAY(isr, KVMLoongArchExtIOI, EXTIOI_IRQS / 32), ++ VMSTATE_UINT32_2DARRAY(coreisr, KVMLoongArchExtIOI, EXTIOI_CPUS, ++ EXTIOI_IRQS_GROUP_COUNT), ++ VMSTATE_UINT32_ARRAY(enable, KVMLoongArchExtIOI, EXTIOI_IRQS / 32), ++ VMSTATE_UINT32_ARRAY(ipmap, KVMLoongArchExtIOI, ++ EXTIOI_IRQS_IPMAP_SIZE / 4), ++ VMSTATE_UINT32_ARRAY(coremap, KVMLoongArchExtIOI, EXTIOI_IRQS / 4), ++ VMSTATE_UINT8_ARRAY(sw_coremap, KVMLoongArchExtIOI, EXTIOI_IRQS), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static void kvm_loongarch_extioi_class_init(ObjectClass *oc, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(oc); ++ KVMLoongArchExtIOIClass *extioi_class = KVM_LOONGARCH_EXTIOI_CLASS(oc); ++ ++ extioi_class->parent_realize = dc->realize; ++ dc->realize = kvm_loongarch_extioi_realize; ++ extioi_class->is_created = false; ++ dc->vmsd = &vmstate_kvm_extioi_core; ++} ++ ++static const TypeInfo kvm_loongarch_extioi_info = { ++ .name = TYPE_KVM_LOONGARCH_EXTIOI, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(KVMLoongArchExtIOI), ++ .class_size = sizeof(KVMLoongArchExtIOIClass), ++ .class_init = kvm_loongarch_extioi_class_init, ++}; ++ ++static void kvm_loongarch_extioi_register_types(void) ++{ ++ type_register_static(&kvm_loongarch_extioi_info); ++} ++ ++type_init(kvm_loongarch_extioi_register_types) +diff --git a/hw/intc/meson.build b/hw/intc/meson.build +index 9deeeb5..a37d7da 100644 +--- a/hw/intc/meson.build ++++ b/hw/intc/meson.build +@@ -74,3 +74,4 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_IPI_KVM', if_true: files('loongarch_ipi_ + specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c')) ++specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI_KVM', if_true: files('loongarch_extioi_kvm.c')) +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index c6e4976..fc86381 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -13,6 +13,7 @@ config LOONGARCH_VIRT + select LOONGARCH_PCH_MSI + select LOONGARCH_EXTIOI + select LOONGARCH_IPI_KVM if KVM ++ select LOONGARCH_EXTIOI_KVM if KVM + select LS7A_RTC + select SMBIOS + select ACPI_CPU_HOTPLUG +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index a570b0d..0b0eb05 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -879,29 +879,33 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + + lvms->ipi = ipi; + +- /* Create EXTIOI device */ +- extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); +- qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.max_cpus); +- if (virt_is_veiointc_enabled(lvms)) { +- qdev_prop_set_bit(extioi, "has-virtualization-extension", true); +- } +- sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); +- memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE, +- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0)); +- if (virt_is_veiointc_enabled(lvms)) { +- memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE, +- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1)); +- } ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ extioi = qdev_new(TYPE_KVM_LOONGARCH_EXTIOI); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); ++ } else { ++ extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); ++ qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.max_cpus); ++ if (virt_is_veiointc_enabled(lvms)) { ++ qdev_prop_set_bit(extioi, "has-virtualization-extension", true); ++ } ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); ++ memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0)); ++ if (virt_is_veiointc_enabled(lvms)) { ++ memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1)); ++ } + +- /* +- * connect ext irq to the cpu irq +- * cpu_pin[9:2] <= intc_pin[7:0] +- */ +- for (cpu = 0; cpu < ms->smp.cpus; cpu++) { +- cpudev = DEVICE(qemu_get_cpu(cpu)); +- for (pin = 0; pin < LS3A_INTC_IP; pin++) { +- qdev_connect_gpio_out(extioi, (cpu * 8 + pin), +- qdev_get_gpio_in(cpudev, pin + 2)); ++ /* ++ * connect ext irq to the cpu irq ++ * cpu_pin[9:2] <= intc_pin[7:0] ++ */ ++ for (cpu = 0; cpu < ms->smp.cpus; cpu++) { ++ cpudev = DEVICE(qemu_get_cpu(cpu)); ++ for (pin = 0; pin < LS3A_INTC_IP; pin++) { ++ qdev_connect_gpio_out(extioi, (cpu * 8 + pin), ++ qdev_get_gpio_in(cpudev, pin + 2)); ++ } + } + } + +diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h +index 626a37d..e8378f60 100644 +--- a/include/hw/intc/loongarch_extioi.h ++++ b/include/hw/intc/loongarch_extioi.h +@@ -15,7 +15,7 @@ + #define EXTIOI_IRQS (256) + #define EXTIOI_IRQS_BITMAP_SIZE (256 / 8) + /* irq from EXTIOI is routed to no more than 4 cpus */ +-#define EXTIOI_CPUS (4) ++#define EXTIOI_CPUS (256) + /* map to ipnum per 32 irqs */ + #define EXTIOI_IRQS_IPMAP_SIZE (256 / 32) + #define EXTIOI_IRQS_COREMAP_SIZE 256 +@@ -58,13 +58,16 @@ + #define EXTIOI_VIRT_COREMAP_START (0x40) + #define EXTIOI_VIRT_COREMAP_END (0x240) + ++#define EXTIOI_SW_COREMAP_FLAG (1 << 0) ++ + typedef struct ExtIOICore { + uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT]; + DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS); + qemu_irq parent_irq[LS3A_INTC_IP]; + } ExtIOICore; + +-#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi" ++#define TYPE_LOONGARCH_EXTIOI "loongarch-extioi" ++#define TYPE_KVM_LOONGARCH_EXTIOI "loongarch-kvm-extioi" + OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI) + struct LoongArchExtIOI { + SysBusDevice parent_obj; +@@ -86,4 +89,31 @@ struct LoongArchExtIOI { + MemoryRegion extioi_system_mem; + MemoryRegion virt_extend; + }; ++ ++struct KVMLoongArchExtIOI { ++ SysBusDevice parent_obj; ++ /* hardware state */ ++ uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2]; ++ uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT]; ++ uint32_t isr[EXTIOI_IRQS / 32]; ++ uint32_t coreisr[EXTIOI_CPUS][EXTIOI_IRQS_GROUP_COUNT]; ++ uint32_t enable[EXTIOI_IRQS / 32]; ++ uint32_t ipmap[EXTIOI_IRQS_IPMAP_SIZE / 4]; ++ uint32_t coremap[EXTIOI_IRQS / 4]; ++ uint8_t sw_coremap[EXTIOI_IRQS]; ++}; ++typedef struct KVMLoongArchExtIOI KVMLoongArchExtIOI; ++DECLARE_INSTANCE_CHECKER(KVMLoongArchExtIOI, KVM_LOONGARCH_EXTIOI, ++ TYPE_KVM_LOONGARCH_EXTIOI) ++ ++struct KVMLoongArchExtIOIClass { ++ SysBusDeviceClass parent_class; ++ DeviceRealize parent_realize; ++ ++ bool is_created; ++ int dev_fd; ++}; ++typedef struct KVMLoongArchExtIOIClass KVMLoongArchExtIOIClass; ++DECLARE_CLASS_CHECKERS(KVMLoongArchExtIOIClass, KVM_LOONGARCH_EXTIOI, ++ TYPE_KVM_LOONGARCH_EXTIOI) + #endif /* LOONGARCH_EXTIOI_H */ +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 25abc23..dce7c50 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -37,6 +37,21 @@ + + #define FDT_BASE 0x100000 + ++/* KVM_IRQ_LINE irq field index values */ ++#define KVM_LOONGARCH_IRQ_TYPE_SHIFT 24 ++#define KVM_LOONGARCH_IRQ_TYPE_MASK 0xff ++#define KVM_LOONGARCH_IRQ_VCPU_SHIFT 16 ++#define KVM_LOONGARCH_IRQ_VCPU_MASK 0xff ++#define KVM_LOONGARCH_IRQ_NUM_SHIFT 0 ++#define KVM_LOONGARCH_IRQ_NUM_MASK 0xffff ++ ++/* irq_type field */ ++#define KVM_LOONGARCH_IRQ_TYPE_CPU_IP 0 ++#define KVM_LOONGARCH_IRQ_TYPE_CPU_IO 1 ++#define KVM_LOONGARCH_IRQ_TYPE_HT 2 ++#define KVM_LOONGARCH_IRQ_TYPE_MSI 3 ++#define KVM_LOONGARCH_IRQ_TYPE_IOAPIC 4 ++ + struct LoongArchVirtMachineState { + /*< private >*/ + MachineState parent_obj; +diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h +index 5fbf4a6..b4f8c2e 100644 +--- a/linux-headers/asm-loongarch/kvm.h ++++ b/linux-headers/asm-loongarch/kvm.h +@@ -150,4 +150,7 @@ struct kvm_iocsr_entry { + #define KVM_LOONGARCH_VM_HAVE_IRQCHIP 0x40000001 + + #define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000002 ++ ++#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000003 ++ + #endif /* __UAPI_ASM_LOONGARCH_KVM_H */ +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index dbe953d..788457f 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1466,6 +1466,8 @@ enum kvm_device_type { + #define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA + KVM_DEV_TYPE_LA_IPI, + #define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI ++ KVM_DEV_TYPE_LA_EXTIOI, ++#define KVM_DEV_TYPE_LA_EXTIOI KVM_DEV_TYPE_LA_EXTIOI + KVM_DEV_TYPE_MAX, + }; + +-- +1.8.3.1 + diff --git a/0266-hw-loongarch-Add-KVM-pch-pic-device-support.patch b/0266-hw-loongarch-Add-KVM-pch-pic-device-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..18f2e3b8a67eab3013bbc48c0ae8ebdfca056e5f --- /dev/null +++ b/0266-hw-loongarch-Add-KVM-pch-pic-device-support.patch @@ -0,0 +1,491 @@ +From 8d4e22880d1a1d5eb0f49a1bf247f49f2b9300b2 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Thu, 7 Mar 2024 20:11:36 +0800 +Subject: [PATCH 276/293] hw/loongarch: Add KVM pch pic device support + +Added pch_pic interrupt controller for kvm emulation. +The main process is to send the command word for +creating an pch_pic device to the kernel, +Delivers the pch pic interrupt controller configuration +register base address to the kernel. +When the VM is saved, the ioctl obtains the pch_pic +interrupt controller data in the kernel and saves it. +When the VM is recovered, the saved data is sent to the kernel. + +Signed-off-by: Xianglai Li +--- + hw/intc/Kconfig | 3 + + hw/intc/loongarch_pch_pic.c | 20 +++- + hw/intc/loongarch_pch_pic_kvm.c | 189 ++++++++++++++++++++++++++++++++++++ + hw/intc/meson.build | 1 + + hw/loongarch/Kconfig | 1 + + hw/loongarch/virt.c | 62 ++++++------ + include/hw/intc/loongarch_pch_pic.h | 51 +++++++++- + linux-headers/asm-loongarch/kvm.h | 5 + + linux-headers/linux/kvm.h | 2 + + 9 files changed, 303 insertions(+), 31 deletions(-) + create mode 100644 hw/intc/loongarch_pch_pic_kvm.c + +diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig +index 3bf0c82..9574ab4 100644 +--- a/hw/intc/Kconfig ++++ b/hw/intc/Kconfig +@@ -100,6 +100,9 @@ config LOONGARCH_PCH_PIC + bool + select UNIMP + ++config LOONGARCH_PCH_PIC_KVM ++ bool ++ + config LOONGARCH_PCH_MSI + select MSI_NONBROKEN + bool +diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c +index 6aa4cad..f801cfe 100644 +--- a/hw/intc/loongarch_pch_pic.c ++++ b/hw/intc/loongarch_pch_pic.c +@@ -16,18 +16,27 @@ + #include "migration/vmstate.h" + #include "trace.h" + #include "qapi/error.h" ++#include "sysemu/kvm.h" + + static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level) + { + uint64_t val; + int irq; ++ int kvm_irq; + + if (level) { + val = mask & s->intirr & ~s->int_mask; + if (val) { + irq = ctz64(val); + s->intisr |= MAKE_64BIT_MASK(irq, 1); +- qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ kvm_irq = ( ++ KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT) ++ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | s->htmsi_vector[irq]; ++ kvm_set_irq(kvm_state, kvm_irq, !!level); ++ } else { ++ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); ++ } + } + } else { + /* +@@ -38,7 +47,14 @@ static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level) + if (val) { + irq = ctz64(val); + s->intisr &= ~MAKE_64BIT_MASK(irq, 1); +- qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0); ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ kvm_irq = ( ++ KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT) ++ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | s->htmsi_vector[irq]; ++ kvm_set_irq(kvm_state, kvm_irq, !!level); ++ } else { ++ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0); ++ } + } + } + } +diff --git a/hw/intc/loongarch_pch_pic_kvm.c b/hw/intc/loongarch_pch_pic_kvm.c +new file mode 100644 +index 0000000..8f66d9a +--- /dev/null ++++ b/hw/intc/loongarch_pch_pic_kvm.c +@@ -0,0 +1,189 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch kvm pch pic interrupt support ++ * ++ * Copyright (C) 2024 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/qdev-properties.h" ++#include "qemu/typedefs.h" ++#include "hw/intc/loongarch_pch_pic.h" ++#include "hw/sysbus.h" ++#include "linux/kvm.h" ++#include "migration/vmstate.h" ++#include "qapi/error.h" ++#include "sysemu/kvm.h" ++#include "hw/loongarch/virt.h" ++#include "hw/pci-host/ls7a.h" ++#include "qemu/error-report.h" ++ ++static void kvm_pch_pic_access_regs(int fd, uint64_t addr, ++ void *val, int is_write) ++{ ++ kvm_device_access(fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS, ++ addr, val, is_write, &error_abort); ++} ++ ++static int kvm_loongarch_pch_pic_pre_save(void *opaque) ++{ ++ KVMLoongArchPCHPIC *s = (KVMLoongArchPCHPIC *)opaque; ++ KVMLoongArchPCHPICClass *class = KVM_LOONGARCH_PCH_PIC_GET_CLASS(s); ++ int fd = class->dev_fd; ++ ++ kvm_pch_pic_access_regs(fd, PCH_PIC_MASK_START, ++ (void *)&s->int_mask, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_EN_START, ++ (void *)&s->htmsi_en, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_EDGE_START, ++ (void *)&s->intedge, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL0_START, ++ (void *)&s->auto_crtl0, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL1_START, ++ (void *)&s->auto_crtl1, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_ROUTE_ENTRY_START, ++ (void *)s->route_entry, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_VEC_START, ++ (void *)s->htmsi_vector, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_IRR_START, ++ (void *)&s->intirr, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_ISR_START, ++ (void *)&s->intisr, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_POLARITY_START, ++ (void *)&s->int_polarity, false); ++ ++ return 0; ++} ++ ++static int kvm_loongarch_pch_pic_post_load(void *opaque, int version_id) ++{ ++ KVMLoongArchPCHPIC *s = (KVMLoongArchPCHPIC *)opaque; ++ KVMLoongArchPCHPICClass *class = KVM_LOONGARCH_PCH_PIC_GET_CLASS(s); ++ int fd = class->dev_fd; ++ ++ kvm_pch_pic_access_regs(fd, PCH_PIC_MASK_START, ++ (void *)&s->int_mask, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_EN_START, ++ (void *)&s->htmsi_en, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_EDGE_START, ++ (void *)&s->intedge, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL0_START, ++ (void *)&s->auto_crtl0, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL1_START, ++ (void *)&s->auto_crtl1, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_ROUTE_ENTRY_START, ++ (void *)s->route_entry, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_VEC_START, ++ (void *)s->htmsi_vector, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_IRR_START, ++ (void *)&s->intirr, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_ISR_START, ++ (void *)&s->intisr, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_POLARITY_START, ++ (void *)&s->int_polarity, true); ++ ++ return 0; ++} ++ ++static void kvm_pch_pic_handler(void *opaque, int irq, int level) ++{ ++ int kvm_irq; ++ ++ if (kvm_enabled()) { ++ kvm_irq = \ ++ (KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT) ++ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | irq; ++ kvm_set_irq(kvm_state, kvm_irq, !!level); ++ } ++} ++ ++static void kvm_loongarch_pch_pic_realize(DeviceState *dev, Error **errp) ++{ ++ KVMLoongArchPCHPICClass *pch_pic_class = ++ KVM_LOONGARCH_PCH_PIC_GET_CLASS(dev); ++ struct kvm_create_device cd = {0}; ++ uint64_t pch_pic_base = VIRT_PCH_REG_BASE; ++ Error *err = NULL; ++ int ret; ++ ++ pch_pic_class->parent_realize(dev, &err); ++ if (err) { ++ error_propagate(errp, err); ++ return; ++ } ++ ++ if (!pch_pic_class->is_created) { ++ cd.type = KVM_DEV_TYPE_LA_PCH_PIC; ++ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); ++ if (ret < 0) { ++ error_setg_errno(errp, errno, ++ "Creating the KVM pch pic device failed"); ++ return; ++ } ++ pch_pic_class->is_created = true; ++ pch_pic_class->dev_fd = cd.fd; ++ fprintf(stdout, "Create LoongArch pch pic irqchip in KVM done!\n"); ++ ++ ret = kvm_device_access(cd.fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL, ++ KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT, ++ &pch_pic_base, true, NULL); ++ if (ret < 0) { ++ error_report( ++ "KVM EXTIOI: failed to set the base address of EXTIOI"); ++ exit(1); ++ } ++ ++ qdev_init_gpio_in(dev, kvm_pch_pic_handler, VIRT_PCH_PIC_IRQ_NUM); ++ } ++} ++ ++static const VMStateDescription vmstate_kvm_loongarch_pch_pic = { ++ .name = TYPE_LOONGARCH_PCH_PIC, ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = kvm_loongarch_pch_pic_pre_save, ++ .post_load = kvm_loongarch_pch_pic_post_load, ++ .fields = (const VMStateField[]) { ++ VMSTATE_UINT64(int_mask, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(htmsi_en, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(intedge, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(intclr, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(auto_crtl0, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(auto_crtl1, KVMLoongArchPCHPIC), ++ VMSTATE_UINT8_ARRAY(route_entry, KVMLoongArchPCHPIC, 64), ++ VMSTATE_UINT8_ARRAY(htmsi_vector, KVMLoongArchPCHPIC, 64), ++ VMSTATE_UINT64(last_intirr, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(intirr, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(intisr, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(int_polarity, KVMLoongArchPCHPIC), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++static void kvm_loongarch_pch_pic_class_init(ObjectClass *oc, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(oc); ++ KVMLoongArchPCHPICClass *pch_pic_class = KVM_LOONGARCH_PCH_PIC_CLASS(oc); ++ ++ pch_pic_class->parent_realize = dc->realize; ++ dc->realize = kvm_loongarch_pch_pic_realize; ++ pch_pic_class->is_created = false; ++ dc->vmsd = &vmstate_kvm_loongarch_pch_pic; ++ ++} ++ ++static const TypeInfo kvm_loongarch_pch_pic_info = { ++ .name = TYPE_KVM_LOONGARCH_PCH_PIC, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(KVMLoongArchPCHPIC), ++ .class_size = sizeof(KVMLoongArchPCHPICClass), ++ .class_init = kvm_loongarch_pch_pic_class_init, ++}; ++ ++static void kvm_loongarch_pch_pic_register_types(void) ++{ ++ type_register_static(&kvm_loongarch_pch_pic_info); ++} ++ ++type_init(kvm_loongarch_pch_pic_register_types) +diff --git a/hw/intc/meson.build b/hw/intc/meson.build +index a37d7da..49b4501 100644 +--- a/hw/intc/meson.build ++++ b/hw/intc/meson.build +@@ -75,3 +75,4 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_ + specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI_KVM', if_true: files('loongarch_extioi_kvm.c')) ++specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC_KVM', if_true: files('loongarch_pch_pic_kvm.c')) +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index fc86381..9b687b4 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -13,6 +13,7 @@ config LOONGARCH_VIRT + select LOONGARCH_PCH_MSI + select LOONGARCH_EXTIOI + select LOONGARCH_IPI_KVM if KVM ++ select LOONGARCH_PCH_PIC_KVM if KVM + select LOONGARCH_EXTIOI_KVM if KVM + select LS7A_RTC + select SMBIOS +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 0b0eb05..2e6d324 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -914,42 +914,48 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + /* Add Extend I/O Interrupt Controller node */ + fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle); + +- pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); +- num = VIRT_PCH_PIC_IRQ_NUM; +- qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num); +- d = SYS_BUS_DEVICE(pch_pic); +- sysbus_realize_and_unref(d, &error_fatal); +- memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE, +- sysbus_mmio_get_region(d, 0)); +- memory_region_add_subregion(get_system_memory(), ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ pch_pic = qdev_new(TYPE_KVM_LOONGARCH_PCH_PIC); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(pch_pic), &error_fatal); ++ } else { ++ pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); ++ num = VIRT_PCH_PIC_IRQ_NUM; ++ qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num); ++ d = SYS_BUS_DEVICE(pch_pic); ++ sysbus_realize_and_unref(d, &error_fatal); ++ memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE, ++ sysbus_mmio_get_region(d, 0)); ++ memory_region_add_subregion(get_system_memory(), + VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET, + sysbus_mmio_get_region(d, 1)); +- memory_region_add_subregion(get_system_memory(), +- VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO, +- sysbus_mmio_get_region(d, 2)); + +- /* Connect pch_pic irqs to extioi */ +- for (i = 0; i < num; i++) { +- qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); ++ memory_region_add_subregion(get_system_memory(), ++ VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO, ++ sysbus_mmio_get_region(d, 2)); ++ ++ /* Connect pch_pic irqs to extioi */ ++ for (i = 0; i < num; i++) { ++ qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); ++ } ++ ++ pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); ++ start = num; ++ num = EXTIOI_IRQS - start; ++ qdev_prop_set_uint32(pch_msi, "msi_irq_base", start); ++ qdev_prop_set_uint32(pch_msi, "msi_irq_num", num); ++ d = SYS_BUS_DEVICE(pch_msi); ++ sysbus_realize_and_unref(d, &error_fatal); ++ sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW); ++ for (i = 0; i < num; i++) { ++ /* Connect pch_msi irqs to extioi */ ++ qdev_connect_gpio_out(DEVICE(d), i, ++ qdev_get_gpio_in(extioi, i + start)); ++ } + } + + /* Add PCH PIC node */ + fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle); + +- pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); +- start = num; +- num = EXTIOI_IRQS - start; +- qdev_prop_set_uint32(pch_msi, "msi_irq_base", start); +- qdev_prop_set_uint32(pch_msi, "msi_irq_num", num); +- d = SYS_BUS_DEVICE(pch_msi); +- sysbus_realize_and_unref(d, &error_fatal); +- sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW); +- for (i = 0; i < num; i++) { +- /* Connect pch_msi irqs to extioi */ +- qdev_connect_gpio_out(DEVICE(d), i, +- qdev_get_gpio_in(extioi, i + start)); +- } +- + /* Add PCH MSI node */ + fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle); + +diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h +index d5437e8..77f4cd7 100644 +--- a/include/hw/intc/loongarch_pch_pic.h ++++ b/include/hw/intc/loongarch_pch_pic.h +@@ -7,7 +7,8 @@ + + #include "hw/sysbus.h" + +-#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic" ++#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic" ++#define TYPE_KVM_LOONGARCH_PCH_PIC "loongarch_kvm_pch_pic" + #define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name + OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC) + +@@ -37,6 +38,19 @@ OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC) + #define PCH_PIC_INT_POL_LO 0x3e0 + #define PCH_PIC_INT_POL_HI 0x3e4 + ++#define PCH_PIC_INT_ID_START PCH_PIC_INT_ID_LO ++#define PCH_PIC_MASK_START PCH_PIC_INT_MASK_LO ++#define PCH_PIC_HTMSI_EN_START PCH_PIC_HTMSI_EN_LO ++#define PCH_PIC_EDGE_START PCH_PIC_INT_EDGE_LO ++#define PCH_PIC_CLEAR_START PCH_PIC_INT_CLEAR_LO ++#define PCH_PIC_AUTO_CTRL0_START PCH_PIC_AUTO_CTRL0_LO ++#define PCH_PIC_AUTO_CTRL1_START PCH_PIC_AUTO_CTRL1_LO ++#define PCH_PIC_ROUTE_ENTRY_START PCH_PIC_ROUTE_ENTRY_OFFSET ++#define PCH_PIC_HTMSI_VEC_START PCH_PIC_HTMSI_VEC_OFFSET ++#define PCH_PIC_INT_IRR_START 0x380 ++#define PCH_PIC_INT_ISR_START PCH_PIC_INT_STATUS_LO ++#define PCH_PIC_POLARITY_START PCH_PIC_INT_POL_LO ++ + #define STATUS_LO_START 0 + #define STATUS_HI_START 0x4 + #define POL_LO_START 0x40 +@@ -67,3 +81,38 @@ struct LoongArchPCHPIC { + MemoryRegion iomem8; + unsigned int irq_num; + }; ++ ++struct KVMLoongArchPCHPIC { ++ SysBusDevice parent_obj; ++ uint64_t int_mask; /*0x020 interrupt mask register*/ ++ uint64_t htmsi_en; /*0x040 1=msi*/ ++ uint64_t intedge; /*0x060 edge=1 level =0*/ ++ uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/ ++ uint64_t auto_crtl0; /*0x0c0*/ ++ uint64_t auto_crtl1; /*0x0e0*/ ++ uint64_t last_intirr; /* edge detection */ ++ uint64_t intirr; /* 0x380 interrupt request register */ ++ uint64_t intisr; /* 0x3a0 interrupt service register */ ++ /* ++ * 0x3e0 interrupt level polarity selection ++ * register 0 for high level trigger ++ */ ++ uint64_t int_polarity; ++ ++ uint8_t route_entry[64]; /*0x100 - 0x138*/ ++ uint8_t htmsi_vector[64]; /*0x200 - 0x238*/ ++}; ++typedef struct KVMLoongArchPCHPIC KVMLoongArchPCHPIC; ++DECLARE_INSTANCE_CHECKER(KVMLoongArchPCHPIC, KVM_LOONGARCH_PCH_PIC, ++ TYPE_KVM_LOONGARCH_PCH_PIC) ++ ++struct KVMLoongArchPCHPICClass { ++ SysBusDeviceClass parent_class; ++ DeviceRealize parent_realize; ++ ++ bool is_created; ++ int dev_fd; ++}; ++typedef struct KVMLoongArchPCHPICClass KVMLoongArchPCHPICClass; ++DECLARE_CLASS_CHECKERS(KVMLoongArchPCHPICClass, KVM_LOONGARCH_PCH_PIC, ++ TYPE_KVM_LOONGARCH_PCH_PIC) +diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h +index b4f8c2e..f109ed4 100644 +--- a/linux-headers/asm-loongarch/kvm.h ++++ b/linux-headers/asm-loongarch/kvm.h +@@ -153,4 +153,9 @@ struct kvm_iocsr_entry { + + #define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000003 + ++#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000004 ++#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0 ++ ++#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 0x40000005 ++ + #endif /* __UAPI_ASM_LOONGARCH_KVM_H */ +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 788457f..f390989 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1464,6 +1464,8 @@ enum kvm_device_type { + #define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME + KVM_DEV_TYPE_RISCV_AIA, + #define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA ++ KVM_DEV_TYPE_LA_PCH_PIC = 0x100, ++#define KVM_DEV_TYPE_LA_PCH_PIC KVM_DEV_TYPE_LA_PCH_PIC + KVM_DEV_TYPE_LA_IPI, + #define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI + KVM_DEV_TYPE_LA_EXTIOI, +-- +1.8.3.1 + diff --git a/0267-hw-loongarch-Add-KVM-pch-msi-device-support.patch b/0267-hw-loongarch-Add-KVM-pch-msi-device-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..b5a787929ac070a230a1a5583c578655fa634080 --- /dev/null +++ b/0267-hw-loongarch-Add-KVM-pch-msi-device-support.patch @@ -0,0 +1,173 @@ +From f0f2e7082e05f79525c7e7d59335335f67f8bdef Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Thu, 7 Mar 2024 20:19:03 +0800 +Subject: [PATCH 277/293] hw/loongarch: Add KVM pch msi device support + +Added pch_msi interrupt controller handling +during kernel emulation of irq chip. + +Signed-off-by: Xianglai Li +--- + hw/intc/loongarch_pch_msi.c | 42 +++++++++++++++++++++++++++---------- + hw/loongarch/virt.c | 28 ++++++++++++++----------- + include/hw/intc/loongarch_pch_msi.h | 2 +- + target/loongarch/kvm/kvm.c | 2 +- + 4 files changed, 49 insertions(+), 25 deletions(-) + +diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c +index ecf3ed0..bab6f85 100644 +--- a/hw/intc/loongarch_pch_msi.c ++++ b/hw/intc/loongarch_pch_msi.c +@@ -2,7 +2,7 @@ + /* + * QEMU Loongson 7A1000 msi interrupt controller. + * +- * Copyright (C) 2021 Loongson Technology Corporation Limited ++ * Copyright (C) 2024 Loongson Technology Corporation Limited + */ + + #include "qemu/osdep.h" +@@ -14,6 +14,8 @@ + #include "hw/misc/unimp.h" + #include "migration/vmstate.h" + #include "trace.h" ++#include "sysemu/kvm.h" ++#include "hw/loongarch/virt.h" + + static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size) + { +@@ -26,14 +28,24 @@ static void loongarch_msi_mem_write(void *opaque, hwaddr addr, + LoongArchPCHMSI *s = (LoongArchPCHMSI *)opaque; + int irq_num; + +- /* +- * vector number is irq number from upper extioi intc +- * need subtract irq base to get msi vector offset +- */ +- irq_num = (val & 0xff) - s->irq_base; +- trace_loongarch_msi_set_irq(irq_num); +- assert(irq_num < s->irq_num); +- qemu_set_irq(s->pch_msi_irq[irq_num], 1); ++ MSIMessage msg = { ++ .address = addr, ++ .data = val, ++ }; ++ ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ kvm_irqchip_send_msi(kvm_state, msg); ++ } else { ++ /* ++ * vector number is irq number from upper extioi intc ++ * need subtract irq base to get msi vector offset ++ */ ++ irq_num = (val & 0xff) - s->irq_base; ++ trace_loongarch_msi_set_irq(irq_num); ++ assert(irq_num < s->irq_num); ++ ++ qemu_set_irq(s->pch_msi_irq[irq_num], 1); ++ } + } + + static const MemoryRegionOps loongarch_pch_msi_ops = { +@@ -45,8 +57,16 @@ static const MemoryRegionOps loongarch_pch_msi_ops = { + static void pch_msi_irq_handler(void *opaque, int irq, int level) + { + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque); +- +- qemu_set_irq(s->pch_msi_irq[irq], level); ++ MSIMessage msg = { ++ .address = 0, ++ .data = irq, ++ }; ++ ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ kvm_irqchip_send_msi(kvm_state, msg); ++ } else { ++ qemu_set_irq(s->pch_msi_irq[irq], level); ++ } + } + + static void loongarch_pch_msi_realize(DeviceState *dev, Error **errp) +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 2e6d324..c7492e5 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -937,29 +937,33 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + for (i = 0; i < num; i++) { + qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); + } ++ } + +- pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); +- start = num; +- num = EXTIOI_IRQS - start; +- qdev_prop_set_uint32(pch_msi, "msi_irq_base", start); +- qdev_prop_set_uint32(pch_msi, "msi_irq_num", num); +- d = SYS_BUS_DEVICE(pch_msi); +- sysbus_realize_and_unref(d, &error_fatal); +- sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW); ++ /* Add PCH PIC node */ ++ fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle); ++ ++ pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); ++ num = VIRT_PCH_PIC_IRQ_NUM; ++ start = num; ++ num = EXTIOI_IRQS - start; ++ qdev_prop_set_uint32(pch_msi, "msi_irq_base", start); ++ qdev_prop_set_uint32(pch_msi, "msi_irq_num", num); ++ d = SYS_BUS_DEVICE(pch_msi); ++ sysbus_realize_and_unref(d, &error_fatal); ++ sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW); ++ if (!(kvm_enabled() && kvm_irqchip_in_kernel())) { ++ /* Connect pch_msi irqs to extioi */ + for (i = 0; i < num; i++) { +- /* Connect pch_msi irqs to extioi */ + qdev_connect_gpio_out(DEVICE(d), i, + qdev_get_gpio_in(extioi, i + start)); + } + } + +- /* Add PCH PIC node */ +- fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle); +- + /* Add PCH MSI node */ + fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle); + + virt_devices_init(pch_pic, lvms, &pch_pic_phandle, &pch_msi_phandle); ++ + } + + static void virt_firmware_init(LoongArchVirtMachineState *lvms) +diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h +index b8586fb..fd4ea97 100644 +--- a/include/hw/intc/loongarch_pch_msi.h ++++ b/include/hw/intc/loongarch_pch_msi.h +@@ -7,7 +7,7 @@ + + #include "hw/sysbus.h" + +-#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi" ++#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi" + OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHMSI, LOONGARCH_PCH_MSI) + + /* MSI irq start from 32 to 255 */ +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index e2e77ab..0ab1ee8 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -962,11 +962,11 @@ int kvm_arch_get_default_type(MachineState *ms) + + int kvm_arch_init(MachineState *ms, KVMState *s) + { +- s->kernel_irqchip_allowed = false; + cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); + if(!kvm_vm_check_attr(kvm_state, KVM_LOONGARCH_VM_HAVE_IRQCHIP, KVM_LOONGARCH_VM_HAVE_IRQCHIP)) { + s->kernel_irqchip_allowed = false; + } ++ s->kernel_irqchip_allowed = false; + + return 0; + } +-- +1.8.3.1 + diff --git a/0268-target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch b/0268-target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch new file mode 100644 index 0000000000000000000000000000000000000000..50e6c25dabe3bc69f19daeed46fd095ad3579b30 --- /dev/null +++ b/0268-target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch @@ -0,0 +1,216 @@ +From 036f2d681ad8cfa3aad7b3fc54c641ed261a4b02 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Mon, 6 May 2024 09:19:12 +0800 +Subject: [PATCH 278/293] target/loongarch: Add TCG macro in structure + CPUArchState + +In structure CPUArchState some struct elements are only used in TCG +mode, and it is not used in KVM mode. Macro CONFIG_TCG is added to +make it simpiler in KVM mode, also there is the same modification +in c code when these structure elements are used. + +When VM runs in KVM mode, TLB entries are not used and do not need +migrate. It is only useful when it runs in TCG mode. + +Signed-off-by: Bibo Mao +Reviewed-by: Richard Henderson +Message-Id: <20240506011912.2108842-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 7 +++++-- + target/loongarch/cpu.h | 15 ++++++++++----- + target/loongarch/cpu_helper.c | 9 +++++++++ + target/loongarch/machine.c | 30 +++++++++++++++++++++++++----- + 4 files changed, 49 insertions(+), 12 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 78f4a95..2a562af 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -527,7 +527,9 @@ static void loongarch_cpu_reset_hold(Object *obj) + lacc->parent_phases.hold(obj); + } + ++#ifdef CONFIG_TCG + env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3; ++#endif + env->fcsr0 = 0x0; + + int n; +@@ -586,7 +588,9 @@ static void loongarch_cpu_reset_hold(Object *obj) + + #ifndef CONFIG_USER_ONLY + env->pc = 0x1c000000; ++#ifdef CONFIG_TCG + memset(env->tlb, 0, sizeof(env->tlb)); ++#endif + if (kvm_enabled()) { + kvm_arch_reset_vcpu(cs); + } +@@ -776,8 +780,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) + int i; + + qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); +- qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0, +- get_float_exception_flags(&env->fp_status)); ++ qemu_fprintf(f, " FCSR0 0x%08x\n", env->fcsr0); + + /* gpr */ + for (i = 0; i < 32; i++) { +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 4a3ae6f..9afa831 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -275,6 +275,7 @@ union fpr_t { + VReg vreg; + }; + ++#ifdef CONFIG_TCG + struct LoongArchTLB { + uint64_t tlb_misc; + /* Fields corresponding to CSR_TLBELO0/1 */ +@@ -282,6 +283,7 @@ struct LoongArchTLB { + uint64_t tlb_entry1; + }; + typedef struct LoongArchTLB LoongArchTLB; ++#endif + + enum loongarch_features { + LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */ +@@ -304,18 +306,13 @@ typedef struct CPUArchState { + uint64_t pc; + + fpr_t fpr[32]; +- float_status fp_status; + bool cf[8]; + + uint32_t fcsr0; + lbt_t lbt; +- uint32_t fcsr0_mask; + + uint32_t cpucfg[21]; + +- uint64_t lladdr; /* LL virtual address compared against SC */ +- uint64_t llval; +- + /* LoongArch CSRs */ + uint64_t CSR_CRMD; + uint64_t CSR_PRMD; +@@ -375,8 +372,16 @@ typedef struct CPUArchState { + uint64_t guest_addr; + } stealtime; + ++#ifdef CONFIG_TCG ++ float_status fp_status; ++ uint32_t fcsr0_mask; ++ uint64_t lladdr; /* LL virtual address compared against SC */ ++ uint64_t llval; ++#endif + #ifndef CONFIG_USER_ONLY ++#ifdef CONFIG_TCG + LoongArchTLB tlb[LOONGARCH_TLB_MAX]; ++#endif + + AddressSpace *address_space_iocsr; + bool load_elf; +diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c +index f68d63f..39037ee 100644 +--- a/target/loongarch/cpu_helper.c ++++ b/target/loongarch/cpu_helper.c +@@ -11,6 +11,7 @@ + #include "internals.h" + #include "cpu-csr.h" + ++#ifdef CONFIG_TCG + static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + int access_type, int index, int mmu_idx) +@@ -154,6 +155,14 @@ static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, + + return TLBRET_NOMATCH; + } ++#else ++static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, ++ int *prot, target_ulong address, ++ MMUAccessType access_type, int mmu_idx) ++{ ++ return TLBRET_NOMATCH; ++} ++#endif + + static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va, + target_ulong dmw) +diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c +index dc76845..818aa71 100644 +--- a/target/loongarch/machine.c ++++ b/target/loongarch/machine.c +@@ -8,6 +8,7 @@ + #include "qemu/osdep.h" + #include "cpu.h" + #include "migration/cpu.h" ++#include "sysemu/tcg.h" + #include "vec.h" + + static const VMStateDescription vmstate_fpu_reg = { +@@ -133,9 +134,15 @@ static const VMStateDescription vmstate_lbt = { + }; + + ++#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) ++static bool tlb_needed(void *opaque) ++{ ++ return tcg_enabled(); ++} ++ + /* TLB state */ +-const VMStateDescription vmstate_tlb = { +- .name = "cpu/tlb", ++static const VMStateDescription vmstate_tlb_entry = { ++ .name = "cpu/tlb_entry", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { +@@ -146,6 +153,19 @@ const VMStateDescription vmstate_tlb = { + } + }; + ++static const VMStateDescription vmstate_tlb = { ++ .name = "cpu/tlb", ++ .version_id = 0, ++ .minimum_version_id = 0, ++ .needed = tlb_needed, ++ .fields = (const VMStateField[]) { ++ VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX, ++ 0, vmstate_tlb_entry, LoongArchTLB), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++#endif ++ + /* LoongArch CPU state */ + const VMStateDescription vmstate_loongarch_cpu = { + .name = "cpu", +@@ -211,9 +231,6 @@ const VMStateDescription vmstate_loongarch_cpu = { + VMSTATE_UINT64(env.CSR_DBG, LoongArchCPU), + VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU), + VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU), +- /* TLB */ +- VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX, +- 0, vmstate_tlb, LoongArchTLB), + + VMSTATE_UINT64(kvm_state_counter, LoongArchCPU), + /* PV steal time */ +@@ -225,6 +242,9 @@ const VMStateDescription vmstate_loongarch_cpu = { + &vmstate_fpu, + &vmstate_lsx, + &vmstate_lasx, ++#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) ++ &vmstate_tlb, ++#endif + &vmstate_lbt, + NULL + } +-- +1.8.3.1 + diff --git a/0269-target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch b/0269-target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch new file mode 100644 index 0000000000000000000000000000000000000000..688298daa8194c3ff24af3baaeed864655ccdb6a --- /dev/null +++ b/0269-target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch @@ -0,0 +1,75 @@ +From 075a7610239e1a8c46c6f479cbc4871620b5b62c Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sun, 28 Apr 2024 11:16:51 +0800 +Subject: [PATCH 279/293] target/loongarch: Put cpucfg operation before CSR + register + +On Loongarch, cpucfg is register for cpu feature, some other registers +depend on cpucfg feature such as perf CSR registers. Here put cpucfg +read/write operations before CSR register, so that KVM knows how many +perf CSR registers are valid from pre-set cpucfg feature information. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240428031651.1354587-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/kvm/kvm.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 0ab1ee8..213cf6a 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -716,6 +716,11 @@ int kvm_arch_get_registers(CPUState *cs) + return ret; + } + ++ ret = kvm_loongarch_get_cpucfg(cs); ++ if (ret) { ++ return ret; ++ } ++ + ret = kvm_loongarch_get_csr(cs); + if (ret) { + return ret; +@@ -737,11 +742,6 @@ int kvm_arch_get_registers(CPUState *cs) + } + + ret = kvm_loongarch_get_mpstate(cs); +- if (ret) { +- return ret; +- } +- +- ret = kvm_loongarch_get_cpucfg(cs); + return ret; + } + +@@ -754,6 +754,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) + return ret; + } + ++ ret = kvm_loongarch_put_cpucfg(cs); ++ if (ret) { ++ return ret; ++ } ++ + ret = kvm_loongarch_put_csr(cs, level); + if (ret) { + return ret; +@@ -781,11 +786,6 @@ int kvm_arch_put_registers(CPUState *cs, int level) + } + + ret = kvm_loongarch_put_mpstate(cs); +- if (ret) { +- return ret; +- } +- +- ret = kvm_loongarch_put_cpucfg(cs); + return ret; + } + +-- +1.8.3.1 + diff --git a/0270-target-loongarch-fixed-a-multi-core-boot-issue.patch b/0270-target-loongarch-fixed-a-multi-core-boot-issue.patch new file mode 100644 index 0000000000000000000000000000000000000000..63acf00b34d21ed2a5c41841365c708c064a3e05 --- /dev/null +++ b/0270-target-loongarch-fixed-a-multi-core-boot-issue.patch @@ -0,0 +1,65 @@ +From 3154802985caaf4241cb59fac3abe63ada5a57ff Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Mon, 28 Oct 2024 20:19:01 +0800 +Subject: [PATCH 280/293] target/loongarch: fixed a multi-core boot issue + +Fixed multiple cpu startup errors and +reboot failure after cpu plug. + +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 2 +- + hw/loongarch/virt.c | 6 +++++- + include/hw/loongarch/virt.h | 1 + + 3 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index cb66870..fb9496d 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -216,7 +216,7 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) + return kernel_entry; + } + +-static void reset_load_elf(void *opaque) ++void reset_load_elf(void *opaque) + { + LoongArchCPU *cpu = opaque; + CPULoongArchState *env = &cpu->env; +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index c7492e5..556af5c 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -875,6 +875,10 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + lacpu = LOONGARCH_CPU(cpu_state); + env = &(lacpu->env); + env->address_space_iocsr = &lvms->as_iocsr; ++ ++ /* connect ipi irq to cpu irq */ ++ qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); ++ env->ipistate = ipi; + } + + lvms->ipi = ipi; +@@ -1511,7 +1515,7 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, + env = &(cpu->env); + env->address_space_iocsr = &lvms->as_iocsr; + +- ++ qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(cs->cpu_index))); + env->ipistate = lvms->ipi; + if (!(kvm_enabled() && kvm_irqchip_in_kernel())) { + /* connect ipi irq to cpu irq, logic cpu index used here */ +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index dce7c50..eb021e2 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -84,4 +84,5 @@ struct LoongArchVirtMachineState { + #define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt") + OBJECT_DECLARE_SIMPLE_TYPE(LoongArchVirtMachineState, LOONGARCH_VIRT_MACHINE) + void loongarch_acpi_setup(LoongArchVirtMachineState *lvms); ++void reset_load_elf(void *opaque); + #endif +-- +1.8.3.1 + diff --git a/0271-hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch b/0271-hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch new file mode 100644 index 0000000000000000000000000000000000000000..5c16aad648528c87415e599407316ba98841eacd --- /dev/null +++ b/0271-hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch @@ -0,0 +1,45 @@ +From 21a0b23baabb2f3d7b8bcbf3945bd0a626399739 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Tue, 29 Oct 2024 15:00:44 +0800 +Subject: [PATCH 281/293] hw/loongarch/boot: Use warn_report when no kernel + filename +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When we run “qemu-system-loongarch64 -qmp stdio -vnc none -S”, +we get an error message “Need kernel filename” and then we can't use qmp cmd to query some information. +So, we just throw a warning and then the cpus starts running from address VIRT_FLASH0_BASE. + +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index fb9496d..53dcefb 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -278,7 +278,7 @@ static void init_boot_rom(struct loongarch_boot_info *info, void *p) + static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) + { + void *p, *bp; +- int64_t kernel_addr = 0; ++ int64_t kernel_addr = VIRT_FLASH0_BASE; + LoongArchCPU *lacpu; + CPUState *cs; + +@@ -286,8 +286,7 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) + kernel_addr = load_kernel_info(info); + } else { + if(!qtest_enabled()) { +- error_report("Need kernel filename\n"); +- exit(1); ++ warn_report("No kernel provided, booting from flash drive."); + } + } + +-- +1.8.3.1 + diff --git a/0272-target-loongarch-fix-Werror-maybe-uninitialized-fals.patch b/0272-target-loongarch-fix-Werror-maybe-uninitialized-fals.patch new file mode 100644 index 0000000000000000000000000000000000000000..9259e535bb466e17b692b10946b1af4a0dc7f0c9 --- /dev/null +++ b/0272-target-loongarch-fix-Werror-maybe-uninitialized-fals.patch @@ -0,0 +1,73 @@ +From 8817f63ff4efca3ab18057cee236e3e27cd19257 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 24 Sep 2024 15:49:47 +0400 +Subject: [PATCH 282/293] target/loongarch: fix -Werror=maybe-uninitialized + false-positive +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../target/loongarch/gdbstub.c:55:20: error: ‘val’ may be used uninitialized [-Werror=maybe-uninitialized] + 55 | return gdb_get_reg32(mem_buf, val); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +../target/loongarch/gdbstub.c:39:18: note: ‘val’ was declared here + 39 | uint64_t val; + +Signed-off-by: Marc-André Lureau +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Xianglai Li +--- + target/loongarch/gdbstub.c | 29 +++++++++++++++-------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c +index 5fc2f19..f8e3324 100644 +--- a/target/loongarch/gdbstub.c ++++ b/target/loongarch/gdbstub.c +@@ -33,28 +33,29 @@ void write_fcc(CPULoongArchState *env, uint64_t val) + + int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) + { +- LoongArchCPU *cpu = LOONGARCH_CPU(cs); +- CPULoongArchState *env = &cpu->env; +- uint64_t val; +- +- if (0 <= n && n < 32) { +- val = env->gpr[n]; +- } else if (n == 32) { +- /* orig_a0 */ +- val = 0; +- } else if (n == 33) { +- val = env->pc; +- } else if (n == 34) { +- val = env->CSR_BADV; +- } ++ CPULoongArchState *env = cpu_env(cs); + + if (0 <= n && n <= 34) { ++ uint64_t val; ++ ++ if (n < 32) { ++ val = env->gpr[n]; ++ } else if (n == 32) { ++ /* orig_a0 */ ++ val = 0; ++ } else if (n == 33) { ++ val = env->pc; ++ } else /* if (n == 34) */ { ++ val = env->CSR_BADV; ++ } ++ + if (is_la64(env)) { + return gdb_get_reg64(mem_buf, val); + } else { + return gdb_get_reg32(mem_buf, val); + } + } ++ + return 0; + } + +-- +1.8.3.1 + diff --git a/0273-target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch b/0273-target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch new file mode 100644 index 0000000000000000000000000000000000000000..370862fd64e1ffb562074e34d5c6282cc7281113 --- /dev/null +++ b/0273-target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch @@ -0,0 +1,65 @@ +From 38205f31340519c705349682fadeea2b17f68cbd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 4 Oct 2024 11:59:56 +0200 +Subject: [PATCH 283/293] target/loongarch: Use explicit little-endian LD/ST + API +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The LoongArch architecture uses little endianness. Directly +use the little-endian LD/ST API. + +Mechanical change using: + + $ end=le; \ + for acc in uw w l q tul; do \ + sed -i -e "s/ld${acc}_p(/ld${acc}_${end}_p(/" \ + -e "s/st${acc}_p(/st${acc}_${end}_p(/" \ + $(git grep -wlE '(ld|st)t?u?[wlq]_p' target/loongarch/); \ + done + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Message-Id: <20241004163042.85922-13-philmd@linaro.org> +Signed-off-by: Xianglai Li +--- + target/loongarch/gdbstub.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c +index f8e3324..cc72680 100644 +--- a/target/loongarch/gdbstub.c ++++ b/target/loongarch/gdbstub.c +@@ -68,10 +68,10 @@ int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) + int length = 0; + + if (is_la64(env)) { +- tmp = ldq_p(mem_buf); ++ tmp = ldq_le_p(mem_buf); + read_length = 8; + } else { +- tmp = ldl_p(mem_buf); ++ tmp = ldl_le_p(mem_buf); + read_length = 4; + } + +@@ -104,13 +104,13 @@ static int loongarch_gdb_set_fpu(CPULoongArchState *env, + int length = 0; + + if (0 <= n && n < 32) { +- env->fpr[n].vreg.D(0) = ldq_p(mem_buf); ++ env->fpr[n].vreg.D(0) = ldq_le_p(mem_buf); + length = 8; + } else if (32 <= n && n < 40) { + env->cf[n - 32] = ldub_p(mem_buf); + length = 1; + } else if (n == 40) { +- env->fcsr0 = ldl_p(mem_buf); ++ env->fcsr0 = ldl_le_p(mem_buf); + length = 4; + } + return length; +-- +1.8.3.1 + diff --git a/0274-target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch b/0274-target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch new file mode 100644 index 0000000000000000000000000000000000000000..a47ea4c436c675d0ad381f7facdfb5ef9da95fee --- /dev/null +++ b/0274-target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch @@ -0,0 +1,56 @@ +From 3e9ae64333b6b29e0fb862acbfd99c6daa432be1 Mon Sep 17 00:00:00 2001 +From: Feiyang Chen +Date: Fri, 28 Jun 2024 13:33:57 +1000 +Subject: [PATCH 284/293] target/loongarch: Remove avail_64 in trans_srai_w() + and simplify it + +Since srai.w is a valid instruction on la32, remove the avail_64 check +and simplify trans_srai_w(). + +Fixes: c0c0461e3a06 ("target/loongarch: Add avail_64 to check la64-only instructions") +Reviewed-by: Richard Henderson +Signed-off-by: Feiyang Chen +Message-Id: <20240628033357.50027-1-chris.chenfeiyang@gmail.com> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/tcg/insn_trans/trans_shift.c.inc | 15 +++------------ + 1 file changed, 3 insertions(+), 12 deletions(-) + +diff --git a/target/loongarch/tcg/insn_trans/trans_shift.c.inc b/target/loongarch/tcg/insn_trans/trans_shift.c.inc +index 2f4bd6f..3773077 100644 +--- a/target/loongarch/tcg/insn_trans/trans_shift.c.inc ++++ b/target/loongarch/tcg/insn_trans/trans_shift.c.inc +@@ -67,19 +67,9 @@ static void gen_rotr_d(TCGv dest, TCGv src1, TCGv src2) + tcg_gen_rotr_tl(dest, src1, t0); + } + +-static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) ++static void gen_sari_w(TCGv dest, TCGv src1, target_long imm) + { +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO); +- +- if (!avail_64(ctx)) { +- return false; +- } +- +- tcg_gen_sextract_tl(dest, src1, a->imm, 32 - a->imm); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; ++ tcg_gen_sextract_tl(dest, src1, imm, 32 - imm); + } + + TRANS(sll_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) +@@ -94,6 +84,7 @@ TRANS(slli_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) + TRANS(slli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) + TRANS(srli_w, ALL, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) + TRANS(srli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) ++TRANS(srai_w, ALL, gen_rri_c, EXT_NONE, EXT_NONE, gen_sari_w) + TRANS(srai_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) + TRANS(rotri_w, 64, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) + TRANS(rotri_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) +-- +1.8.3.1 + diff --git a/0275-target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch b/0275-target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch new file mode 100644 index 0000000000000000000000000000000000000000..39498ddfaf68ed665832f9527b5062c3310e63a1 --- /dev/null +++ b/0275-target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch @@ -0,0 +1,56 @@ +From f2afd64d1f35e1bfbd2836c45d7d8d9871a55bc5 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 5 Jul 2024 10:18:38 +0800 +Subject: [PATCH 285/293] target/loongarch: Set CSR_PRCFG1 and CSR_PRCFG2 + values + +We set the value of register CSR_PRCFG3, but left out CSR_PRCFG1 +and CSR_PRCFG2. Set CSR_PRCFG1 and CSR_PRCFG2 according to the +default values of the physical machine. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240705021839.1004374-1-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 2a562af..b80dde5 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -463,6 +463,18 @@ static void loongarch_la464_initfn(Object *obj) + env->cpucfg[20] = data; + + env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa); ++ ++ env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM, 8); ++ env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, TIMER_BITS, 0x2f); ++ env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, VSMAX, 7); ++ ++ env->CSR_PRCFG2 = 0x3ffff000; ++ ++ env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); ++ env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); ++ env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); ++ env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); ++ + loongarch_cpu_post_init(obj); + } + +@@ -574,11 +586,6 @@ static void loongarch_cpu_reset_hold(Object *obj) + env->CSR_TLBRENTRY = 0; + env->CSR_MERRENTRY = 0; + +- env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); +- env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); +- env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); +- env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); +- + for (n = 0; n < 4; n++) { + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0); + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0); +-- +1.8.3.1 + diff --git a/0276-target-loongarch-fix-a-wrong-print-in-cpu-dump.patch b/0276-target-loongarch-fix-a-wrong-print-in-cpu-dump.patch new file mode 100644 index 0000000000000000000000000000000000000000..43d971858864f8ef04cf3fea6a4e5d49b88bbf1a --- /dev/null +++ b/0276-target-loongarch-fix-a-wrong-print-in-cpu-dump.patch @@ -0,0 +1,49 @@ +From 4e2073adb37295cab18c97ed5101fafd8bb28872 Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 11:27:12 +0800 +Subject: [PATCH 286/293] target/loongarch: fix a wrong print in cpu dump + +cherry picked from commit 78f932ea1f7b3b9b0ac628dc2a91281318fe51fa + +description: + loongarch_cpu_dump_state() want to dump all loongarch cpu +state registers, but there is a tiny typographical error when +printing "PRCFG2". + +Cc: qemu-stable@nongnu.org +Signed-off-by: lanyanzhi +Reviewed-by: Richard Henderson +Reviewed-by: Song Gao +Message-Id: <20240604073831.666690-1-lanyanzhi22b@ict.ac.cn> +Signed-off-by: Song Gao +Signed-off-by: Gao Jiazhen +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index b80dde5..bfc7df3 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -91,7 +91,7 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env, + { + CPUState *cs = env_cpu(env); + +- qemu_log_mask(CPU_LOG_INT, "%s: expection: %d (%s)\n", ++ qemu_log_mask(CPU_LOG_INT, "%s: exception: %d (%s)\n", + __func__, + exception, + loongarch_exception_name(exception)); +@@ -810,7 +810,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) + qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY); + qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 "," + " PRCFG3=%016" PRIx64 "\n", +- env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3); ++ env->CSR_PRCFG1, env->CSR_PRCFG2, env->CSR_PRCFG3); + qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY); + qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV); + qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA); +-- +1.8.3.1 + diff --git a/0277-loongarch-switch-boards-to-default-y.patch b/0277-loongarch-switch-boards-to-default-y.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb5a1dce81df95b306addd10c72890bd1ccfecd0 --- /dev/null +++ b/0277-loongarch-switch-boards-to-default-y.patch @@ -0,0 +1,60 @@ +From 7b1de30924d4569bd64a52fd7b4499d2ab90ffe3 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 25 Jan 2024 13:36:37 +0100 +Subject: [PATCH 287/293] loongarch: switch boards to "default y" + +Some targets use "default y" for boards to filter out those that require +TCG. For consistency we are switching all other targets to do the same. +Continue with Loongarch. + +No changes to generated config-devices.mak file. + +Signed-off-by: Paolo Bonzini +Signed-off-by: Xianglai Li +--- + .gitlab-ci.d/buildtest.yml | 2 ++ + configs/devices/loongarch64-softmmu/default.mak | 6 +++++- + hw/loongarch/Kconfig | 2 ++ + 3 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml +index 0a01746..e39e327 100644 +--- a/.gitlab-ci.d/buildtest.yml ++++ b/.gitlab-ci.d/buildtest.yml +@@ -579,6 +579,8 @@ build-tci: + - make check-tcg + + # Check our reduced build configurations ++# requires libfdt: aarch64, arm, i386, loongarch64, x86_64 ++# does not build without boards: i386, loongarch64, x86_64 + build-without-defaults: + extends: .native_build_job_template + needs: +diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak +index 928bc11..ffe7058 100644 +--- a/configs/devices/loongarch64-softmmu/default.mak ++++ b/configs/devices/loongarch64-softmmu/default.mak +@@ -1,3 +1,7 @@ + # Default configuration for loongarch64-softmmu + +-CONFIG_LOONGARCH_VIRT=y ++# Uncomment the following lines to disable these optional devices: ++# CONFIG_PCI_DEVICES=n ++ ++# Boards are selected by default, uncomment to keep out of the build. ++# CONFIG_LOONGARCH_VIRT=n +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index 9b687b4..16c854c 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -1,5 +1,7 @@ + config LOONGARCH_VIRT + bool ++ default y ++ depends on LOONGARCH64 + select PCI + select PCI_EXPRESS_GENERIC_BRIDGE + imply PCI_DEVICES +-- +1.8.3.1 + diff --git a/0278-tests-libqos-Add-loongarch-virt-machine-node.patch b/0278-tests-libqos-Add-loongarch-virt-machine-node.patch new file mode 100644 index 0000000000000000000000000000000000000000..272288f1be6f4dd12b553548715fe3f815eb62ab --- /dev/null +++ b/0278-tests-libqos-Add-loongarch-virt-machine-node.patch @@ -0,0 +1,162 @@ +From 6c733d918decbc5db37c1110ff96cde50d29d118 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 28 May 2024 16:20:53 +0800 +Subject: [PATCH 288/293] tests/libqos: Add loongarch virt machine node + +Add loongarch virt machine to the graph. It is a modified copy of +the existing riscv virtmachine in riscv-virt-machine.c + +It contains a generic-pcihost controller, and an extra function +loongarch_config_qpci_bus() to configure GPEX pci host controller +information, such as ecam and pio_base addresses. + +Also hotplug handle checking about TYPE_VIRTIO_IOMMU_PCI device is +added on loongarch virt machine, since virtio_mmu_pci device requires +it. + +Signed-off-by: Bibo Mao +Acked-by: Thomas Huth +Message-Id: <20240528082053.938564-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + tests/qtest/libqos/loongarch-virt-machine.c | 114 ++++++++++++++++++++++++++++ + tests/qtest/libqos/meson.build | 1 + + 2 files changed, 115 insertions(+) + create mode 100644 tests/qtest/libqos/loongarch-virt-machine.c + +diff --git a/tests/qtest/libqos/loongarch-virt-machine.c b/tests/qtest/libqos/loongarch-virt-machine.c +new file mode 100644 +index 0000000..c12089c +--- /dev/null ++++ b/tests/qtest/libqos/loongarch-virt-machine.c +@@ -0,0 +1,114 @@ ++/* ++ * libqos driver framework ++ * ++ * Copyright (c) 2018 Emanuele Giuseppe Esposito ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License version 2.1 as published by the Free Software Foundation. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see ++ */ ++ ++#include "qemu/osdep.h" ++#include "../libqtest.h" ++#include "qemu/module.h" ++#include "libqos-malloc.h" ++#include "qgraph.h" ++#include "virtio-mmio.h" ++#include "generic-pcihost.h" ++#include "hw/pci/pci_regs.h" ++ ++#define LOONGARCH_PAGE_SIZE 0x1000 ++#define LOONGARCH_VIRT_RAM_ADDR 0x100000 ++#define LOONGARCH_VIRT_RAM_SIZE 0xFF00000 ++ ++#define LOONGARCH_VIRT_PIO_BASE 0x18000000 ++#define LOONGARCH_VIRT_PCIE_PIO_OFFSET 0x4000 ++#define LOONGARCH_VIRT_PCIE_PIO_LIMIT 0x10000 ++#define LOONGARCH_VIRT_PCIE_ECAM_BASE 0x20000000 ++#define LOONGARCH_VIRT_PCIE_MMIO32_BASE 0x40000000 ++#define LOONGARCH_VIRT_PCIE_MMIO32_LIMIT 0x80000000 ++ ++typedef struct QVirtMachine QVirtMachine; ++ ++struct QVirtMachine { ++ QOSGraphObject obj; ++ QGuestAllocator alloc; ++ QVirtioMMIODevice virtio_mmio; ++ QGenericPCIHost bridge; ++}; ++ ++static void virt_destructor(QOSGraphObject *obj) ++{ ++ QVirtMachine *machine = (QVirtMachine *) obj; ++ alloc_destroy(&machine->alloc); ++} ++ ++static void *virt_get_driver(void *object, const char *interface) ++{ ++ QVirtMachine *machine = object; ++ if (!g_strcmp0(interface, "memory")) { ++ return &machine->alloc; ++ } ++ ++ fprintf(stderr, "%s not present in loongarch/virtio\n", interface); ++ g_assert_not_reached(); ++} ++ ++static QOSGraphObject *virt_get_device(void *obj, const char *device) ++{ ++ QVirtMachine *machine = obj; ++ if (!g_strcmp0(device, "generic-pcihost")) { ++ return &machine->bridge.obj; ++ } else if (!g_strcmp0(device, "virtio-mmio")) { ++ return &machine->virtio_mmio.obj; ++ } ++ ++ fprintf(stderr, "%s not present in loongarch/virt\n", device); ++ g_assert_not_reached(); ++} ++ ++static void loongarch_config_qpci_bus(QGenericPCIBus *qpci) ++{ ++ qpci->gpex_pio_base = LOONGARCH_VIRT_PIO_BASE; ++ qpci->bus.pio_alloc_ptr = LOONGARCH_VIRT_PCIE_PIO_OFFSET; ++ qpci->bus.pio_limit = LOONGARCH_VIRT_PCIE_PIO_LIMIT; ++ qpci->bus.mmio_alloc_ptr = LOONGARCH_VIRT_PCIE_MMIO32_BASE; ++ qpci->bus.mmio_limit = LOONGARCH_VIRT_PCIE_MMIO32_LIMIT; ++ qpci->ecam_alloc_ptr = LOONGARCH_VIRT_PCIE_ECAM_BASE; ++} ++ ++static void *qos_create_machine_loongarch_virt(QTestState *qts) ++{ ++ QVirtMachine *machine = g_new0(QVirtMachine, 1); ++ ++ alloc_init(&machine->alloc, 0, ++ LOONGARCH_VIRT_RAM_ADDR, ++ LOONGARCH_VIRT_RAM_ADDR + LOONGARCH_VIRT_RAM_SIZE, ++ LOONGARCH_PAGE_SIZE); ++ ++ qos_create_generic_pcihost(&machine->bridge, qts, &machine->alloc); ++ loongarch_config_qpci_bus(&machine->bridge.pci); ++ ++ machine->obj.get_device = virt_get_device; ++ machine->obj.get_driver = virt_get_driver; ++ machine->obj.destructor = virt_destructor; ++ return machine; ++} ++ ++static void virt_machine_register_nodes(void) ++{ ++ qos_node_create_machine_args("loongarch64/virt", ++ qos_create_machine_loongarch_virt, ++ " -cpu la464"); ++ qos_node_contains("loongarch64/virt", "generic-pcihost", NULL); ++} ++ ++libqos_init(virt_machine_register_nodes); +diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build +index 90aae42..482c9b2 100644 +--- a/tests/qtest/libqos/meson.build ++++ b/tests/qtest/libqos/meson.build +@@ -60,6 +60,7 @@ libqos_srcs = files( + 'arm-xilinx-zynq-a9-machine.c', + 'ppc64_pseries-machine.c', + 'x86_64_pc-machine.c', ++ 'loongarch-virt-machine.c', + ) + + if have_virtfs +-- +1.8.3.1 + diff --git a/0279-target-loongarch-kvm-Add-software-breakpoint-support.patch b/0279-target-loongarch-kvm-Add-software-breakpoint-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..9f9a231d5f57189b1bdd71038d7ffb1c24930fd5 --- /dev/null +++ b/0279-target-loongarch-kvm-Add-software-breakpoint-support.patch @@ -0,0 +1,39 @@ +From 718f9f6636aa7957550bddec46d434c91c0199f8 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Fri, 7 Jun 2024 11:50:16 +0800 +Subject: [PATCH 289/293] target/loongarch/kvm: Add software breakpoint support + +With KVM virtualization, debug exception is injected to guest kernel +rather than host for normal break intruction. Here hypercall +instruction with special code is used for sw breakpoint usage, +and detailed instruction comes from kvm kernel with user API +KVM_REG_LOONGARCH_DEBUG_INST. + +Now only software breakpoint is supported, and it is allowed to +insert/remove software breakpoint. We can debug guest kernel with gdb +method after kernel is loaded, hardware breakpoint will be added in later. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Tested-by: Song Gao +Message-Id: <20240607035016.2975799-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + configs/targets/loongarch64-softmmu.mak | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak +index f23780f..0034c33 100644 +--- a/configs/targets/loongarch64-softmmu.mak ++++ b/configs/targets/loongarch64-softmmu.mak +@@ -1,5 +1,6 @@ + TARGET_ARCH=loongarch64 + TARGET_BASE_ARCH=loongarch ++TARGET_KVM_HAVE_GUEST_DEBUG=y + TARGET_SUPPORTS_MTTCG=y + TARGET_XML_FILES= gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml + TARGET_NEED_FDT=y +-- +1.8.3.1 + diff --git a/0280-enable-the-irqchip-simulation-function.patch b/0280-enable-the-irqchip-simulation-function.patch new file mode 100644 index 0000000000000000000000000000000000000000..dca6c800a6773249c615c27f22b1e6b4ce64bebd --- /dev/null +++ b/0280-enable-the-irqchip-simulation-function.patch @@ -0,0 +1,58 @@ +From 2fe48cc942c4d4100679ef11f614fb4803d440c8 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Mon, 4 Nov 2024 16:42:15 +0800 +Subject: [PATCH 290/293] enable the irqchip simulation function + +Enable the irqchip kernel simulation function, +Fixed a bug when using irqchip emulation. + +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 11 ++++++++--- + target/loongarch/kvm/kvm.c | 1 - + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 556af5c..d165c23 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -864,6 +864,14 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0)); + memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR, + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1)); ++ ++ for (cpu = 0; cpu < ms->smp.cpus; cpu++) { ++ cpu_state = qemu_get_cpu(cpu); ++ cpudev = DEVICE(cpu_state); ++ ++ /* connect ipi irq to cpu irq */ ++ qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); ++ } + } + + /* Add cpu interrupt-controller */ +@@ -875,9 +883,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + lacpu = LOONGARCH_CPU(cpu_state); + env = &(lacpu->env); + env->address_space_iocsr = &lvms->as_iocsr; +- +- /* connect ipi irq to cpu irq */ +- qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); + env->ipistate = ipi; + } + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 213cf6a..719d6c2 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -966,7 +966,6 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + if(!kvm_vm_check_attr(kvm_state, KVM_LOONGARCH_VM_HAVE_IRQCHIP, KVM_LOONGARCH_VM_HAVE_IRQCHIP)) { + s->kernel_irqchip_allowed = false; + } +- s->kernel_irqchip_allowed = false; + + return 0; + } +-- +1.8.3.1 + diff --git a/0281-hw-i386-pc-add-mem2-option-for-qemu.patch b/0281-hw-i386-pc-add-mem2-option-for-qemu.patch new file mode 100644 index 0000000000000000000000000000000000000000..8358c061d8323ec420152a030cc4af94d62aabbd --- /dev/null +++ b/0281-hw-i386-pc-add-mem2-option-for-qemu.patch @@ -0,0 +1,311 @@ +From a0bd22be312157e80e2300f0001342625592db3c Mon Sep 17 00:00:00 2001 +From: xiongmengbiao +Date: Wed, 29 May 2024 00:05:44 +0800 +Subject: [PATCH 291/293] hw/i386/pc: add mem2 option for qemu + +The '-mem2' option is used to create a set of hugepages +of memory and map them to a fixed address range of the guest. + +This allows some devices to easily obtain continuous host +physical address ranges for performing DMA operations. + +Signed-off-by: xiongmengbiao +--- + hw/i386/pc.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + include/hw/boards.h | 2 + + qemu-options.hx | 12 +++++ + system/vl.c | 67 ++++++++++++++++++++++++++- + 4 files changed, 209 insertions(+), 1 deletion(-) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 29b9964..2bf0341 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -743,6 +743,119 @@ void xen_load_linux(PCMachineState *pcms) + x86ms->fw_cfg = fw_cfg; + } + ++static int try_create_2MB_page(uint32_t page_num) ++{ ++ char nr_hp_num_s[256] = {0}; ++ char free_hp_num_s[256] = {0}; ++ const char *nr_hugepages_dir = "/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages"; ++ const char *free_hugepages_dir = "/sys/kernel/mm/hugepages/hugepages-2048kB/free_hugepages"; ++ int nr_hp_num = -1, free_hp_num = -1, ret = -1; ++ int nr_fd = qemu_open_old(nr_hugepages_dir, O_RDWR); ++ int free_fd = qemu_open_old(free_hugepages_dir, O_RDONLY); ++ ++ if (nr_fd < 0 || free_fd < 0) { ++ error_report("%s: qemu_open failed: %s\n", __func__, strerror(errno)); ++ goto end; ++ } ++ ++ if (read(nr_fd, nr_hp_num_s, 256) < 0) ++ goto end; ++ if (read(free_fd, free_hp_num_s, 256) < 0) ++ goto end; ++ ++ nr_hp_num = atoi(nr_hp_num_s); ++ free_hp_num = atoi(free_hp_num_s); ++ if (nr_hp_num < 0 || free_hp_num < 0) ++ goto end; ++ ++ if (page_num <= free_hp_num) { ++ ret = 0; ++ goto end; ++ } ++ ++ nr_hp_num += (page_num - free_hp_num); ++ snprintf (nr_hp_num_s, 256, "%d", nr_hp_num); ++ if (write(nr_fd, nr_hp_num_s, strlen(nr_hp_num_s)) < 0) ++ goto end; ++ ++ ret = 0; ++end: ++ if (nr_fd >= 0) ++ qemu_close(nr_fd); ++ if (free_fd >= 0) ++ qemu_close(free_fd); ++ return ret; ++} ++ ++#define HUGEPAGE_NUM_MAX 128 ++#define HUGEPAGE_SIZE (1024*1024*2) ++static void mem2_init(MachineState *ms, MemoryRegion *system_memory) ++{ ++ MemoryRegion *mem2_mr[HUGEPAGE_NUM_MAX] = {NULL}; ++ char mr_name[128] = {0}; ++ void *ram = NULL; ++ int ret = 0, lock_fd = 0; ++ const char *lock_file = "/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages"; ++ uint32_t page_num = ms->ram2_size / HUGEPAGE_SIZE, i; ++ ++ if (HUGEPAGE_NUM_MAX < page_num) { ++ error_report("\"-mem2 'size='\" needs to Less than %dM\n", ++ (HUGEPAGE_SIZE * HUGEPAGE_NUM_MAX) / (1024 * 1024)); ++ exit(EXIT_FAILURE); ++ } ++ ++ // Apply for hugepages from OS and use them, which needs to be synchronized ++ lock_fd = qemu_open_old(lock_file, O_WRONLY); ++ if (lock_fd < 0) { ++ error_report("%s: open %s failed: %s\n", __func__, lock_file, strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ ++ // Non-blocking ++ while (qemu_lock_fd(lock_fd, 0, 0, true)) { ++ if (errno != EACCES && errno != EAGAIN) { ++ error_report("qemu_lock_fd failed: %s\n", strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ } ++ ++ /** try to create hugepage. ++ * If there are enough free hugepages, then do nothing. ++ */ ++ ret = try_create_2MB_page(page_num); ++ if (ret) { ++ error_report("%s: Failed to allocate hugepage\n", __func__); ++ goto unlock; ++ } ++ ++ for (i = 0; i < page_num; ++i) { ++ mem2_mr[i] = g_malloc(sizeof(MemoryRegion)); ++ ram = mmap(NULL, HUGEPAGE_SIZE, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0); ++ if (ram == MAP_FAILED) { ++ error_report("%s: mmap failed: %s", __func__, strerror(errno)); ++ goto unlock; ++ } ++ ++ sprintf(mr_name, "mem2-%d", i); ++ memory_region_init_ram_ptr(mem2_mr[i], NULL, mr_name, HUGEPAGE_SIZE, ram); ++ memory_region_add_subregion(system_memory, ms->ram2_base + (i * HUGEPAGE_SIZE), mem2_mr[i]); ++ } ++ ++ ret = 0; ++unlock: ++ qemu_unlock_fd(lock_fd, 0, 0); ++ qemu_close(lock_fd); ++ ++ if (ret) { ++ for (i = 0; i < page_num; ++i) { ++ if (mem2_mr[i]) ++ g_free(mem2_mr[i]); ++ } ++ exit(EXIT_FAILURE); ++ } ++} ++ + #define PC_ROM_MIN_VGA 0xc0000 + #define PC_ROM_MIN_OPTION 0xc8000 + #define PC_ROM_MAX 0xe0000 +@@ -965,6 +1078,22 @@ void pc_memory_init(PCMachineState *pcms, + E820_RAM); + } + ++ if (machine->ram2_size && machine->ram2_base) { ++ if (0x100000000ULL + x86ms->above_4g_mem_size > machine->ram2_base) { ++ error_report("\"-mem2 'base'\" needs to greater 0x%llx\n", ++ 0x100000000ULL + x86ms->above_4g_mem_size); ++ exit(EXIT_FAILURE); ++ } ++ if (machine->ram2_base & (HUGEPAGE_SIZE - 1) || ++ machine->ram2_size & (HUGEPAGE_SIZE - 1)) { ++ error_report("\"-mem2 'base|size'\" needs to aligned to 0x%x\n", HUGEPAGE_SIZE); ++ exit(EXIT_FAILURE); ++ } ++ ++ mem2_init(machine, system_memory); ++ e820_add_entry(machine->ram2_base, machine->ram2_size, E820_RAM); ++ } ++ + if (pcms->sgx_epc.size != 0) { + e820_add_entry(pcms->sgx_epc.base, pcms->sgx_epc.size, E820_RESERVED); + } +diff --git a/include/hw/boards.h b/include/hw/boards.h +index da85f86..8ac8cad 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -389,6 +389,8 @@ struct MachineState { + + ram_addr_t ram_size; + ram_addr_t maxram_size; ++ ram_addr_t ram2_base; ++ ram_addr_t ram2_size; + uint64_t ram_slots; + BootConfiguration boot_config; + char *kernel_filename; +diff --git a/qemu-options.hx b/qemu-options.hx +index c260117..caeca1d 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -5856,6 +5856,18 @@ SRST + (qemu) qom-set /objects/iothread1 poll-max-ns 100000 + ERST + ++DEF("mem2", HAS_ARG, QEMU_OPTION_mem2, ++ "-mem2 base=addr[G],size=n[MG]\n" ++ " Map guest memory using host hugepages\n" ++ " base: starting position of guest physical address\n" ++ " size: the size of mmaped memory\n" ++ "NOTE: Both `base` and `size` need to be aligned according to 2MB\n", ++ QEMU_ARCH_I386) ++SRST ++``-mem2 base=addr[G],size=n[MG]`` ++ Map the host's large page memory at the specified guest address ++ so that some devices can use larger contiguous physical memory. ++ERST + + HXCOMM This is the last statement. Insert new options before this line! + +diff --git a/system/vl.c b/system/vl.c +index e18fa3c..101c2df 100644 +--- a/system/vl.c ++++ b/system/vl.c +@@ -503,6 +503,23 @@ static QemuOptsList qemu_action_opts = { + }, + }; + ++static QemuOptsList qemu_mem2_opts = { ++ .name = "mem2", ++ .merge_lists = true, ++ .head = QTAILQ_HEAD_INITIALIZER(qemu_mem2_opts.head), ++ .desc = { ++ { ++ .name = "base", ++ .type = QEMU_OPT_SIZE, ++ }, ++ { ++ .name = "size", ++ .type = QEMU_OPT_SIZE, ++ }, ++ { /* end of list */ } ++ }, ++}; ++ + const char *qemu_get_vm_name(void) + { + return qemu_name; +@@ -2090,6 +2107,45 @@ static void parse_memory_options(void) + loc_pop(&loc); + } + ++static void parse_mem2_options(void) ++{ ++ uint64_t sz, base; ++ const char *sz_str = NULL, *base_str = NULL; ++ QemuOpts *opts = qemu_find_opts_singleton("mem2"); ++ Location loc; ++ ++ loc_push_none(&loc); ++ qemu_opts_loc_restore(opts); ++ ++ base_str = qemu_opt_get(opts, "base"); ++ sz_str = qemu_opt_get(opts, "size"); ++ ++ if (!base_str && !sz_str) ++ return; ++ ++ if ((!base_str || !*base_str) ++ || (!sz_str || !*sz_str)) { ++ error_report("missing 'base' or 'size' argument for -mem2 option"); ++ exit(EXIT_FAILURE); ++ } ++ ++ base = qemu_opt_get_size(opts, "base", 0); ++ if (!base) { ++ error_report("invalid 'base' value\n"); ++ exit(EXIT_FAILURE); ++ } ++ current_machine->ram2_base = base; ++ ++ sz = qemu_opt_get_size(opts, "size", 0); ++ if (!sz) { ++ error_report("invalid 'size' value\n"); ++ exit(EXIT_FAILURE); ++ } ++ current_machine->ram2_size = sz; ++ ++ loc_pop(&loc); ++} ++ + static void qemu_create_machine(QDict *qdict) + { + MachineClass *machine_class = select_machine(qdict, &error_fatal); +@@ -2776,6 +2832,7 @@ void qemu_init(int argc, char **argv) + qemu_add_opts(&qemu_semihosting_config_opts); + qemu_add_opts(&qemu_fw_cfg_opts); + qemu_add_opts(&qemu_action_opts); ++ qemu_add_opts(&qemu_mem2_opts); + qemu_add_run_with_opts(); + module_call_init(MODULE_INIT_OPTS); + +@@ -3635,7 +3692,13 @@ void qemu_init(int argc, char **argv) + break; + } + #endif /* CONFIG_POSIX */ +- ++ case QEMU_OPTION_mem2: ++ opts = qemu_opts_parse_noisily(qemu_find_opts("mem2"), ++ optarg, false); ++ if (!opts) { ++ exit(EXIT_FAILURE); ++ } ++ break; + default: + error_report("Option not supported in this build"); + exit(1); +@@ -3686,6 +3749,8 @@ void qemu_init(int argc, char **argv) + + qemu_create_machine(machine_opts_dict); + ++ parse_mem2_options(); ++ + suspend_mux_open(); + + qemu_disable_default_devices(); +-- +1.8.3.1 + diff --git a/0282-hw-misc-psp-support-tkm-use-mem2-memory.patch b/0282-hw-misc-psp-support-tkm-use-mem2-memory.patch new file mode 100644 index 0000000000000000000000000000000000000000..4c71c1edcb2baf425ce3652b7e0a05b3f080a5b8 --- /dev/null +++ b/0282-hw-misc-psp-support-tkm-use-mem2-memory.patch @@ -0,0 +1,124 @@ +From f0fa769d19ee604c0cc026f3ccfabd5d932cb681 Mon Sep 17 00:00:00 2001 +From: xiongmengbiao +Date: Wed, 29 May 2024 15:18:55 +0800 +Subject: [PATCH 292/293] hw/misc/psp: support tkm use mem2 memory + +Change-Id: I04c76eb27eb7c097922d61b893a47b18f55bcd66 +Signed-off-by: xiongmengbiao +--- + hw/misc/psp.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 63 insertions(+), 1 deletion(-) + +diff --git a/hw/misc/psp.c b/hw/misc/psp.c +index da0a69e..85e4455 100644 +--- a/hw/misc/psp.c ++++ b/hw/misc/psp.c +@@ -15,6 +15,9 @@ + #include "migration/vmstate.h" + #include "hw/qdev-properties.h" + #include "sysemu/runstate.h" ++#include "exec/memory.h" ++#include "exec/address-spaces.h" ++#include "hw/i386/e820_memory_layout.h" + #include + + #define TYPE_PSP_DEV "psp" +@@ -46,14 +49,24 @@ struct PSPDevState { + enum VPSP_DEV_CTRL_OPCODE { + VPSP_OP_VID_ADD, + VPSP_OP_VID_DEL, ++ VPSP_OP_SET_DEFAULT_VID_PERMISSION, ++ VPSP_OP_GET_DEFAULT_VID_PERMISSION, ++ VPSP_OP_SET_GPA, + }; + + struct psp_dev_ctrl { + unsigned char op; ++ unsigned char resv[3]; + union { + unsigned int vid; ++ // Set or check the permissions for the default VID ++ unsigned int def_vid_perm; ++ struct { ++ uint64_t gpa_start; ++ uint64_t gpa_end; ++ } gpa; + unsigned char reserved[128]; +- } data; ++ } __attribute__ ((packed)) data; + }; + + static void psp_dev_destroy(PSPDevState *state) +@@ -86,10 +99,32 @@ static void psp_dev_shutdown_notify(Notifier *notifier, void *data) + psp_dev_destroy(state); + } + ++static MemoryRegion *find_memory_region_by_name(MemoryRegion *root, const char *name) { ++ MemoryRegion *subregion; ++ MemoryRegion *result; ++ ++ if (strcmp(root->name, name) == 0) ++ return root; ++ ++ QTAILQ_FOREACH(subregion, &root->subregions, subregions_link) { ++ result = find_memory_region_by_name(subregion, name); ++ if (result) { ++ return result; ++ } ++ } ++ ++ return NULL; ++} ++ + static void psp_dev_realize(DeviceState *dev, Error **errp) + { ++ int i; ++ char mr_name[128] = {0}; + struct psp_dev_ctrl ctrl = { 0 }; + PSPDevState *state = PSP_DEV(dev); ++ MemoryRegion *root_mr = get_system_memory(); ++ MemoryRegion *find_mr = NULL; ++ uint64_t ram2_start = 0, ram2_end = 0; + + state->dev_fd = qemu_open_old(PSP_DEV_PATH, O_RDWR); + if (state->dev_fd < 0) { +@@ -104,9 +139,36 @@ static void psp_dev_realize(DeviceState *dev, Error **errp) + goto end; + } + ++ for (i = 0 ;; ++i) { ++ sprintf(mr_name, "mem2-%d", i); ++ find_mr = find_memory_region_by_name(root_mr, mr_name); ++ if (!find_mr) ++ break; ++ ++ if (!ram2_start) ++ ram2_start = find_mr->addr; ++ ram2_end = find_mr->addr + find_mr->size - 1; ++ } ++ ++ if (ram2_start != ram2_end) { ++ ctrl.op = VPSP_OP_SET_GPA; ++ ctrl.data.gpa.gpa_start = ram2_start; ++ ctrl.data.gpa.gpa_end = ram2_end; ++ if (ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl) < 0) { ++ error_setg(errp, "psp_dev_realize VPSP_OP_SET_GPA (start 0x%lx, end 0x%lx), return %d", ++ ram2_start, ram2_end, -errno); ++ goto del_vid; ++ } ++ } ++ + state->enabled = true; + state->shutdown_notifier.notify = psp_dev_shutdown_notify; + qemu_register_shutdown_notifier(&state->shutdown_notifier); ++ ++ return; ++del_vid: ++ ctrl.op = VPSP_OP_VID_DEL; ++ ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl); + end: + return; + } +-- +1.8.3.1 + diff --git a/0283-hw-misc-psp-Pin-the-hugepage-memory-specified-by-mem.patch b/0283-hw-misc-psp-Pin-the-hugepage-memory-specified-by-mem.patch new file mode 100644 index 0000000000000000000000000000000000000000..85120216f1e4df83c3a956519c55b1d372671cdf --- /dev/null +++ b/0283-hw-misc-psp-Pin-the-hugepage-memory-specified-by-mem.patch @@ -0,0 +1,213 @@ +From 25cde42855442fd9a7f00255c936838ebc5cfb45 Mon Sep 17 00:00:00 2001 +From: niuyongwen +Date: Sun, 29 Sep 2024 09:45:15 +0800 +Subject: [PATCH 293/293] hw/misc/psp: Pin the hugepage memory specified by + mem2 during use for psp + +Change-Id: I3ada4a3f9d12361dc11318c56c1601dfdc4b2ed7 +Signed-off-by: niuyongwen +--- + hw/misc/psp.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 121 insertions(+), 17 deletions(-) + +diff --git a/hw/misc/psp.c b/hw/misc/psp.c +index 85e4455..c2af21d 100644 +--- a/hw/misc/psp.c ++++ b/hw/misc/psp.c +@@ -17,6 +17,7 @@ + #include "sysemu/runstate.h" + #include "exec/memory.h" + #include "exec/address-spaces.h" ++#include "exec/ramblock.h" + #include "hw/i386/e820_memory_layout.h" + #include + +@@ -38,6 +39,8 @@ struct PSPDevState { + * the TKM module uses different key spaces based on different vids. + */ + uint32_t vid; ++ /* pinned hugepage numbers */ ++ int hp_num; + }; + + #define PSP_DEV_PATH "/dev/hygon_psp_config" +@@ -45,6 +48,8 @@ struct PSPDevState { + #define PSP_IOC_MUTEX_ENABLE _IOWR(HYGON_PSP_IOC_TYPE, 1, NULL) + #define PSP_IOC_MUTEX_DISABLE _IOWR(HYGON_PSP_IOC_TYPE, 2, NULL) + #define PSP_IOC_VPSP_OPT _IOWR(HYGON_PSP_IOC_TYPE, 3, NULL) ++#define PSP_IOC_PIN_USER_PAGE _IOWR(HYGON_PSP_IOC_TYPE, 4, NULL) ++#define PSP_IOC_UNPIN_USER_PAGE _IOWR(HYGON_PSP_IOC_TYPE, 5, NULL) + + enum VPSP_DEV_CTRL_OPCODE { + VPSP_OP_VID_ADD, +@@ -69,6 +74,109 @@ struct psp_dev_ctrl { + } __attribute__ ((packed)) data; + }; + ++static MemoryRegion *find_memory_region_by_name(MemoryRegion *root, const char *name) { ++ MemoryRegion *subregion; ++ MemoryRegion *result; ++ ++ if (strcmp(root->name, name) == 0) ++ return root; ++ ++ QTAILQ_FOREACH(subregion, &root->subregions, subregions_link) { ++ result = find_memory_region_by_name(subregion, name); ++ if (result) { ++ return result; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int pin_user_hugepage(int fd, uint64_t vaddr) ++{ ++ int ret; ++ ++ ret = ioctl(fd, PSP_IOC_PIN_USER_PAGE, vaddr); ++ /* 22: Invalid argument, some old kernel doesn't support this ioctl command */ ++ if (ret != 0 && errno == EINVAL) { ++ ret = 0; ++ } ++ return ret; ++} ++ ++static int unpin_user_hugepage(int fd, uint64_t vaddr) ++{ ++ int ret; ++ ++ ret = ioctl(fd, PSP_IOC_UNPIN_USER_PAGE, vaddr); ++ /* 22: Invalid argument, some old kernel doesn't support this ioctl command */ ++ if (ret != 0 && errno == EINVAL) { ++ ret = 0; ++ } ++ return ret; ++} ++ ++static int pin_psp_user_hugepages(struct PSPDevState *state, MemoryRegion *root) ++{ ++ int ret = 0; ++ char mr_name[128] = {0}; ++ int i, pinned_num; ++ MemoryRegion *find_mr = NULL; ++ ++ for (i = 0 ; i < state->hp_num; ++i) { ++ sprintf(mr_name, "mem2-%d", i); ++ find_mr = find_memory_region_by_name(root, mr_name); ++ if (!find_mr) { ++ error_report("fail to find memory region by name %s.", mr_name); ++ ret = -ENOMEM; ++ goto end; ++ } ++ ++ ret = pin_user_hugepage(state->dev_fd, (uint64_t)find_mr->ram_block->host); ++ if (ret) { ++ error_report("fail to pin_user_hugepage, ret: %d.", ret); ++ goto end; ++ } ++ } ++end: ++ if (ret) { ++ pinned_num = i; ++ for (i = 0 ; i < pinned_num; ++i) { ++ sprintf(mr_name, "mem2-%d", i); ++ find_mr = find_memory_region_by_name(root, mr_name); ++ if (!find_mr) { ++ continue; ++ } ++ unpin_user_hugepage(state->dev_fd, (uint64_t)find_mr->ram_block->host); ++ } ++ ++ } ++ return ret; ++} ++ ++static int unpin_psp_user_hugepages(struct PSPDevState *state, MemoryRegion *root) ++{ ++ int ret = 0; ++ char mr_name[128] = {0}; ++ int i; ++ MemoryRegion *find_mr = NULL; ++ ++ for (i = 0 ; i < state->hp_num; ++i) { ++ sprintf(mr_name, "mem2-%d", i); ++ find_mr = find_memory_region_by_name(root, mr_name); ++ if (!find_mr) { ++ continue; ++ } ++ ++ ret = unpin_user_hugepage(state->dev_fd, (uint64_t)find_mr->ram_block->host); ++ if (ret) { ++ error_report("fail to unpin_user_hugepage, ret: %d.", ret); ++ goto end; ++ } ++ } ++end: ++ return ret; ++} ++ + static void psp_dev_destroy(PSPDevState *state) + { + struct psp_dev_ctrl ctrl = { 0 }; +@@ -77,6 +185,11 @@ static void psp_dev_destroy(PSPDevState *state) + ctrl.op = VPSP_OP_VID_DEL; + if (ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl) < 0) { + error_report("VPSP_OP_VID_DEL: %d", -errno); ++ } ++ ++ /* Unpin hugepage memory */ ++ if (unpin_psp_user_hugepages(state, get_system_memory())) { ++ error_report("unpin_psp_user_hugepages failed"); + } else { + state->enabled = false; + } +@@ -99,23 +212,6 @@ static void psp_dev_shutdown_notify(Notifier *notifier, void *data) + psp_dev_destroy(state); + } + +-static MemoryRegion *find_memory_region_by_name(MemoryRegion *root, const char *name) { +- MemoryRegion *subregion; +- MemoryRegion *result; +- +- if (strcmp(root->name, name) == 0) +- return root; +- +- QTAILQ_FOREACH(subregion, &root->subregions, subregions_link) { +- result = find_memory_region_by_name(subregion, name); +- if (result) { +- return result; +- } +- } +- +- return NULL; +-} +- + static void psp_dev_realize(DeviceState *dev, Error **errp) + { + int i; +@@ -150,6 +246,8 @@ static void psp_dev_realize(DeviceState *dev, Error **errp) + ram2_end = find_mr->addr + find_mr->size - 1; + } + ++ state->hp_num = i; ++ + if (ram2_start != ram2_end) { + ctrl.op = VPSP_OP_SET_GPA; + ctrl.data.gpa.gpa_start = ram2_start; +@@ -159,6 +257,12 @@ static void psp_dev_realize(DeviceState *dev, Error **errp) + ram2_start, ram2_end, -errno); + goto del_vid; + } ++ ++ /* Pin hugepage memory */ ++ if(pin_psp_user_hugepages(state, root_mr)) { ++ error_setg(errp, "pin_psp_user_hugepages failed."); ++ goto del_vid; ++ } + } + + state->enabled = true; +-- +1.8.3.1 + diff --git a/0284-fix-potential-use-after-free-with-dbus-shared-memory.patch b/0284-fix-potential-use-after-free-with-dbus-shared-memory.patch new file mode 100644 index 0000000000000000000000000000000000000000..b183644223b6f939744b5593d1836c90a34f8d57 --- /dev/null +++ b/0284-fix-potential-use-after-free-with-dbus-shared-memory.patch @@ -0,0 +1,165 @@ +From 448119b4bdf75ec88d5dbbe1238a6dba6b1863aa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 8 Oct 2024 16:50:13 +0400 +Subject: [PATCH] ui/win32: fix potential use-after-free with dbus shared + memory +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +DisplaySurface may be free before the pixman image is freed, since the +image is refcounted and used by different objects, including pending +dbus messages. + +Furthermore, setting the destroy function in +create_displaysurface_from() isn't appropriate, as it may not be used, +and may be overriden as in ramfb. + +Set the destroy function when the shared handle is set, use the HANDLE +directly for destroy data, using a single common helper +qemu_pixman_win32_image_destroy(). + +Signed-off-by: Marc-André Lureau +Reviewed-by: Akihiko Odaki +Message-ID: <20241008125028.1177932-5-marcandre.lureau@redhat.com> +--- + hw/display/virtio-gpu.c | 14 ++------------ + include/ui/qemu-pixman.h | 2 ++ + ui/console.c | 24 ++---------------------- + ui/qemu-pixman.c | 15 +++++++++++++++ + 4 files changed, 21 insertions(+), 34 deletions(-) + +diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c +index b016d3bac85..d4f946eb763 100644 +--- a/hw/display/virtio-gpu.c ++++ b/hw/display/virtio-gpu.c +@@ -239,16 +239,6 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat, + return height * stride; + } + +-#ifdef WIN32 +-static void +-win32_pixman_image_destroy(pixman_image_t *image, void *data) +-{ +- HANDLE handle = data; +- +- qemu_win32_map_free(pixman_image_get_data(image), handle, &error_warn); +-} +-#endif +- + static void virtio_gpu_resource_create_2d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) + { +@@ -309,7 +299,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, + bits, c2d.height ? res->hostmem / c2d.height : 0); + #ifdef WIN32 + if (res->image) { +- pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle); ++ pixman_image_set_destroy_function(res->image, qemu_pixman_win32_image_destroy, res->handle); + } + #endif + } +@@ -1303,7 +1293,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, + return -EINVAL; + } + #ifdef WIN32 +- pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle); ++ pixman_image_set_destroy_function(res->image, qemu_pixman_win32_image_destroy, res->handle); + #endif + + res->addrs = g_new(uint64_t, res->iov_cnt); +diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h +index ef13a8210cc..e3dd72b9e38 100644 +--- a/include/ui/qemu-pixman.h ++++ b/include/ui/qemu-pixman.h +@@ -97,6 +97,8 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph, + + void qemu_pixman_image_unref(pixman_image_t *image); + ++void qemu_pixman_win32_image_destroy(pixman_image_t *image, void *data); ++ + G_DEFINE_AUTOPTR_CLEANUP_FUNC(pixman_image_t, qemu_pixman_image_unref) + + #endif /* QEMU_PIXMAN_H */ +diff --git a/ui/console.c b/ui/console.c +index 832055675c5..c462b8f2280 100644 +--- a/ui/console.c ++++ b/ui/console.c +@@ -504,24 +504,6 @@ void qemu_displaysurface_win32_set_handle(DisplaySurface *surface, + surface->handle = h; + surface->handle_offset = offset; + } +- +-static void +-win32_pixman_image_destroy(pixman_image_t *image, void *data) +-{ +- DisplaySurface *surface = data; +- +- if (!surface->handle) { +- return; +- } +- +- assert(surface->handle_offset == 0); +- +- qemu_win32_map_free( +- pixman_image_get_data(surface->image), +- surface->handle, +- &error_warn +- ); +-} + #endif + + DisplaySurface *qemu_create_displaysurface(int width, int height) +@@ -547,6 +529,8 @@ DisplaySurface *qemu_create_displaysurface(int width, int height) + + #ifdef WIN32 + qemu_displaysurface_win32_set_handle(surface, handle, 0); ++ pixman_image_set_destroy_function(surface->image, ++ qemu_pixman_win32_image_destroy, handle); + #endif + return surface; + } +@@ -562,10 +546,6 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height, + width, height, + (void *)data, linesize); + assert(surface->image != NULL); +-#ifdef WIN32 +- pixman_image_set_destroy_function(surface->image, +- win32_pixman_image_destroy, surface); +-#endif + + return surface; + } +diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c +index 5ca55dd1998..de6c88151c2 100644 +--- a/ui/qemu-pixman.c ++++ b/ui/qemu-pixman.c +@@ -4,6 +4,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qapi/error.h" + #include "ui/console.h" + #include "standard-headers/drm/drm_fourcc.h" + #include "trace.h" +@@ -268,3 +269,17 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph, + pixman_image_unref(ibg); + } + #endif /* CONFIG_PIXMAN */ ++ ++#ifdef WIN32 ++void ++qemu_pixman_win32_image_destroy(pixman_image_t *image, void *data) ++{ ++ HANDLE handle = data; ++ ++ qemu_win32_map_free( ++ pixman_image_get_data(image), ++ handle, ++ &error_warn ++ ); ++} ++#endif +-- +Gitee + diff --git a/0285-fix-CVE-2024-7730.patch b/0285-fix-CVE-2024-7730.patch new file mode 100644 index 0000000000000000000000000000000000000000..f70125aaa79abea210c3a159381452556863fe2f --- /dev/null +++ b/0285-fix-CVE-2024-7730.patch @@ -0,0 +1,57 @@ +From 98e77e3dd8dd6e7aa9a7dffa60f49c8c8a49d4e3 Mon Sep 17 00:00:00 2001 +From: Manos Pitsidianakis +Date: Mon, 8 Jul 2024 10:09:49 +0300 +Subject: [PATCH] virtio-snd: add max size bounds check in input cb +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When reading input audio in the virtio-snd input callback, +virtio_snd_pcm_in_cb(), we do not check whether the iov can actually fit +the data buffer. This is because we use the buffer->size field as a +total-so-far accumulator instead of byte-size-left like in TX buffers. + +This triggers an out of bounds write if the size of the virtio queue +element is equal to virtio_snd_pcm_status, which makes the available +space for audio data zero. This commit adds a check for reaching the +maximum buffer size before attempting any writes. + +Reported-by: Zheyu Ma +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2427 +Signed-off-by: Manos Pitsidianakis +Message-Id: +Reviewed-by: Philippe Mathieu-Daud茅 +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/audio/virtio-snd.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c +index 5993f4f0407..e6432ac959a 100644 +--- a/hw/audio/virtio-snd.c ++++ b/hw/audio/virtio-snd.c +@@ -1261,7 +1261,7 @@ static void virtio_snd_pcm_in_cb(void *data, int available) + { + VirtIOSoundPCMStream *stream = data; + VirtIOSoundPCMBuffer *buffer; +- size_t size; ++ size_t size, max_size; + + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + while (!QSIMPLEQ_EMPTY(&stream->queue)) { +@@ -1275,7 +1275,12 @@ static void virtio_snd_pcm_in_cb(void *data, int available) + continue; + } + ++ max_size = iov_size(buffer->elem->in_sg, buffer->elem->in_num); + for (;;) { ++ if (buffer->size >= max_size) { ++ return_rx_buffer(stream, buffer); ++ break; ++ } + size = AUD_read(stream->voice.in, + buffer->data + buffer->size, + MIN(available, (stream->params.period_bytes - +-- +GitLab diff --git a/qemu.spec b/qemu.spec index 03a27014a4b818b04d86e1d8ca6dbac9d4420549..fbfd0f0f78cdc14ac92413dd1713b525ff8e68cb 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,7 +1,19 @@ -%define anolis_release 14 - +%define anolis_release 26 %bcond_with check +%global all_system_emu_support 0 +%if 0%{?all_system_emu_support} != 1 +%ifarch x86_64 +%global target_list x86_64-linux-user,x86_64-softmmu +%endif +%ifarch aarch64 +%global target_list aarch64-linux-user,aarch64_be-linux-user,aarch64-softmmu +%endif +%ifarch loongarch64 +%global target_list loongarch64-linux-user,loongarch64-softmmu +%endif + +%endif %global libfdt_version 1.6.0 %global libseccomp_version 2.3.0 %global libusbx_version 1.0.23 @@ -45,7 +57,7 @@ # Matches spice ExclusiveArch %global have_spice 0 -%ifarch x86_64 aarch64 +%ifarch x86_64 aarch64 loongarch64 %global have_spice 1 %endif @@ -73,7 +85,11 @@ %global have_edk2 1 # All modules should be listed here. +%ifarch loongarch64 +%define have_block_rbd 1 +%else %define have_block_rbd 0 +%endif %global have_block_gluster 1 @@ -183,12 +199,16 @@ %{requires_ui_spice_core} \ %{requires_char_baum} \ %{requires_char_spice} \ +%ifnarch aarch64 loongarch64 \ %{requires_device_display_qxl} \ +%endif \ %{requires_device_display_vhost_user_gpu} \ %{requires_device_display_virtio_gpu} \ %{requires_device_display_virtio_gpu_pci} \ +%ifnarch aarch64 loongarch64 \ %{requires_device_display_virtio_vga} \ %{requires_device_display_virtio_vga_gl} \ +%endif \ %{requires_device_usb_host} \ %{requires_device_usb_redirect} \ %{requires_device_usb_smartcard} \ @@ -262,98 +282,293 @@ Source27: kvm.conf Source31: kvm-x86.conf Source36: README.tests -Patch0001: 0001-sgx-stub-fix.patch -Patch0002: 0002-Fix-crash-when-loading-snapshot-on-inactive-node.patch - -Patch0003: 0003-hw-loongarch-virt-Align-high-memory-base-address-wit.patch -Patch0004: 0004-target-loongarch-Add-timer-information-dump-support.patch -Patch0005: 0005-target-loongarch-meson-move-gdbstub.c-to-loongarch.s.patch -Patch0006: 0006-target-loongarch-move-translate-modules-to-tcg.patch -Patch0007: 0007-linux-headers-Update-to-Linux-v6.7-rc5.patch -Patch0008: 0008-linux-headers-Synchronize-linux-headers-from-linux-v.patch -Patch0009: 0009-target-loongarch-Define-some-kvm_arch-interfaces.patch -Patch0010: 0010-target-loongarch-Supplement-vcpu-env-initial-when-vc.patch -Patch0011: 0011-target-loongarch-Implement-kvm-get-set-registers.patch -Patch0012: 0012-target-loongarch-Implement-kvm_arch_init-function.patch -Patch0013: 0013-target-loongarch-Implement-kvm_arch_init_vcpu.patch -Patch0014: 0014-target-loongarch-Implement-kvm_arch_handle_exit.patch -Patch0015: 0015-target-loongarch-Restrict-TCG-specific-code.patch -Patch0016: 0016-target-loongarch-Implement-set-vcpu-intr-for-kvm.patch -Patch0017: 0017-target-loongarch-Add-loongarch-kvm-into-meson-build.patch -Patch0018: 0018-hw-intc-loongarch_ipi-Use-MemTxAttrs-interface-for-i.patch -Patch0019: 0019-hw-loongarch-virt-Set-iocsr-address-space-per-board-.patch -Patch0020: 0020-hw-intc-loongarch_extioi-Add-dynamic-cpu-number-supp.patch -Patch0021: 0021-hw-intc-loongarch_extioi-Add-vmstate-post_load-suppo.patch -Patch0022: 0022-configure-Add-linux-header-compile-support-for-Loong.patch -Patch0023: 0023-target-loongarch-Set-cpuid-CSR-register-only-once-wi.patch -Patch0024: 0024-target-loongarch-kvm-Enable-LSX-LASX-extension.patch -Patch0025: 0025-target-loongarch-Fix-qtest-test-hmp-error-when-KVM-o.patch -Patch0026: 0026-loongarch-Change-the-UEFI-loading-mode-to-loongarch.patch -Patch0027: 0027-target-loongarch-Fix-tlb-huge-page-loading-issue.patch -Patch0028: 0028-target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch -Patch0029: 0029-target-loongarch-kvm-Add-software-breakpoint-support.patch -Patch0030: 0030-hw-intc-loongarch_extioi-Add-virt-extension-support.patch -Patch0031: 0031-target-loongarch-kvm-sync-kernel-header-files.patch -Patch0032: 0032-hw-intc-loongarch_extioi-Add-virt-extension-support-.patch -Patch0033: 0033-target-loongarch-kvm-Add-pmu-support.patch -Patch0034: 0034-target-loongarch-Fix-qemu-system-loongarch64-assert-.patch - -Patch0035: 0035-newfeature-support-vpsp.patch - -Patch0036: 0036-target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch -Patch0037: 0037-target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch - -Patch1001: 1001-i386-cpu-Clear-FEAT_XSAVE_XSS_LO-HI-leafs-when-CPUID.patch -Patch1002: 1002-i386-cpu-Mask-with-XCR0-XSS-mask-for-FEAT_XSAVE_XCR0.patch -Patch1003: 1003-i386-cpuid-Decrease-cpuid_i-when-skipping-CPUID-leaf.patch -Patch1004: 1004-i386-cpuid-Move-leaf-7-to-correct-group.patch - -Patch1005: 1005-doc-update-AMD-SEV-to-include-Live-migration-flow.patch -Patch1006: 1006-migration.json-add-AMD-SEV-specific-migration-parame.patch -Patch1007: 1007-confidential-guest-support-introduce-ConfidentialGue.patch -Patch1008: 1008-target-i386-sev-provide-callback-to-setup-outgoing-c.patch -Patch1009: 1009-target-i386-sev-do-not-create-launch-context-for-an-.patch -Patch1010: 1010-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch -Patch1011: 1011-target-i386-sev-add-support-to-load-incoming-encrypt.patch -Patch1012: 1012-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch -Patch1013: 1013-migration-add-support-to-migrate-shared-regions-list.patch -Patch1014: 1014-migration-ram-add-support-to-send-encrypted-pages.patch -Patch1015: 1015-migration-ram-Force-encrypted-status-for-flash0-flas.patch -Patch1016: 1016-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch -Patch1017: 1017-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch -Patch1018: 1018-migration-ram-Force-encrypted-status-for-VGA-vram.patch -Patch1019: 1019-target-i386-sev-Clear-shared_regions_list-when-reboo.patch -Patch1020: 1020-migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch -Patch1021: 1021-target-i386-Introduce-header-file-csv.h.patch -Patch1022: 1022-target-i386-csv-Read-cert-chain-from-file-when-prepa.patch -Patch1023: 1023-target-i386-csv-add-support-to-queue-the-outgoing-pa.patch -Patch1024: 1024-target-i386-csv-add-support-to-encrypt-the-outgoing-.patch -Patch1025: 1025-target-i386-csv-add-support-to-queue-the-incoming-pa.patch -Patch1026: 1026-target-i386-csv-add-support-to-load-incoming-encrypt.patch -Patch1027: 1027-migration-ram-Accelerate-the-transmission-of-CSV-gue.patch -Patch1028: 1028-migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch -Patch1029: 1029-target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch -Patch1030: 1030-target-i386-get-set-migrate-GHCB-state.patch -Patch1031: 1031-target-i386-kvm-Fix-the-resettable-info-when-emulate.patch -Patch1032: 1032-kvm-Add-support-for-CSV2-reboot.patch -Patch1033: 1033-target-i386-csv-Add-CSV3-context.patch -Patch1034: 1034-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch -Patch1035: 1035-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch -Patch1036: 1036-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch -Patch1037: 1037-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch -Patch1038: 1038-target-i386-csv-Do-not-register-unregister-guest-sec.patch -Patch1039: 1039-target-i386-csv-Load-initial-image-to-private-memory.patch -Patch1040: 1040-vga-Force-full-update-for-CSV3-guest.patch -Patch1041: 1041-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch -Patch1042: 1042-linux-headers-update-kernel-headers-to-include-CSV3-.patch -Patch1043: 1043-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch -Patch1044: 1044-target-i386-csv-Add-support-to-migrate-the-incoming-.patch -Patch1045: 1045-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch -Patch1046: 1046-target-i386-csv-Add-support-to-migrate-the-incoming-.patch -Patch1047: 1047-target-i386-sev-Fix-incompatibility-between-SEV-and-.patch -Patch1048: 1048-target-i386-sev-Add-support-for-reuse-ASID-for-diffe.patch -Patch1049: 1049-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch -Patch1050: 1050-target-i386-Add-new-Hygon-Dharma-CPU-model.patch +#qemu patch +Patch0001: 0001-block-Fix-crash-when-loading-snapshot-on-inactive-no.patch +Patch0002: 0002-vl-Improve-error-message-for-conflicting-incoming-an.patch +Patch0003: 0003-iotests-Basic-tests-for-internal-snapshots.patch +Patch0004: 0004-target-riscv-kvm-do-not-use-non-portable-strerrornam.patch +Patch0005: 0005-include-ui-rect.h-fix-qemu_rect_init-mis-assignment.patch +Patch0006: 0006-configure-use-a-native-non-cross-compiler-for-linux-.patch +Patch0007: 0007-target-i386-the-sgx_epc_get_section-stub-is-reachabl.patch +Patch0008: 0008-hw-net-can-sja1000-fix-bug-for-single-acceptance-fil.patch +Patch0009: 0009-target-riscv-Fix-mcycle-minstret-increment-behavior.patch +Patch0010: 0010-chardev-char.c-fix-abstract-device-type-error-messag.patch +Patch0011: 0011-audio-audio.c-remove-trailing-newline-in-error_setg.patch +Patch0012: 0012-hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch +Patch0013: 0013-edu-fix-DMA-range-upper-bound-check.patch +Patch0014: 0014-vfio-container-Replace-basename-with-g_path_get_base.patch +Patch0015: 0015-hw-vfio-fix-iteration-over-global-VFIODevice-list.patch +Patch0016: 0016-hw-intc-arm_gicv3_cpuif-handle-LPIs-in-in-the-list-r.patch +Patch0017: 0017-tcg-ppc-Use-new-registers-for-LQ-destination.patch +Patch0018: 0018-util-fix-build-with-musl-libc-on-ppc64le.patch +Patch0019: 0019-tests-acpi-allow-tests-data-acpi-virt-SSDT.memhp-cha.patch +Patch0020: 0020-edk2-update-build-config-set-PcdUninstallMemAttrProt.patch +Patch0021: 0021-tests-acpi-disallow-tests-data-acpi-virt-SSDT.memhp-.patch +Patch0022: 0022-tests-qtest-virtio-ccw-Fix-device-presence-checking.patch +Patch0023: 0023-target-s390x-Fix-LAE-setting-a-wrong-access-register.patch +Patch0024: 0024-.gitlab-ci.d-buildtest.yml-Work-around-htags-bug-whe.patch +Patch0025: 0025-readthodocs-fully-specify-a-build-environment.patch +Patch0026: 0026-hw-hppa-machine-Allow-up-to-3840-MB-total-memory.patch +Patch0027: 0027-hw-hppa-machine-Disable-default-devices-with-nodefau.patch +Patch0028: 0028-hw-pci-host-astro-Add-missing-astro-elroy-registers-.patch +Patch0029: 0029-hw-hppa-Move-software-power-button-address-back-into.patch +Patch0030: 0030-target-hppa-Avoid-accessing-gr0-when-raising-excepti.patch +Patch0031: 0031-target-hppa-Export-function-hppa_set_ior_and_isr.patch +Patch0032: 0032-target-hppa-Fix-IOR-and-ISR-on-unaligned-access-trap.patch +Patch0033: 0033-target-hppa-Fix-IOR-and-ISR-on-error-in-probe.patch +Patch0034: 0034-load_elf-fix-iterator-s-type-for-elf-file-processing.patch +Patch0035: 0035-target-i386-Do-not-re-compute-new-pc-with-CF_PCREL.patch +Patch0036: 0036-target-i386-fix-incorrect-EIP-in-PC-relative-transla.patch +Patch0037: 0037-target-i386-pcrel-store-low-bits-of-physical-address.patch +Patch0038: 0038-backends-cryptodev-Do-not-ignore-throttle-backends-E.patch +Patch0039: 0039-hw-pflash-refactor-pflash_data_write.patch +Patch0040: 0040-hw-pflash-use-ldn_-be-le-_p-and-stn_-be-le-_p.patch +Patch0041: 0041-hw-pflash-implement-update-buffer-for-block-writes.patch +Patch0042: 0042-migration-rdma-define-htonll-ntohll-only-if-not-pred.patch +Patch0043: 0043-hw-scsi-esp-pci-use-correct-address-register-for-PCI.patch +Patch0044: 0044-hw-scsi-esp-pci-generate-PCI-interrupt-from-separate.patch +Patch0045: 0045-hw-scsi-esp-pci-synchronise-setting-of-DMA_STAT_DONE.patch +Patch0046: 0046-hw-scsi-esp-pci-set-DMA_STAT_BCMBLT-when-BLAST-comma.patch +Patch0047: 0047-s390x-pci-avoid-double-enable-disable-of-aif.patch +Patch0048: 0048-s390x-pci-refresh-fh-before-disabling-aif.patch +Patch0049: 0049-s390x-pci-drive-ISM-reset-from-subsystem-reset.patch +Patch0050: 0050-acpi-tests-avocado-bits-wait-for-200-seconds-for-SHU.patch +Patch0051: 0051-accel-tcg-Revert-mapping-of-PCREL-translation-block-.patch +Patch0052: 0052-tcg-s390x-Fix-encoding-of-VRIc-VRSa-VRSc-insns.patch +Patch0053: 0053-coroutine-ucontext-Save-fake-stack-for-pooled-corout.patch +Patch0054: 0054-block-io-clear-BDRV_BLOCK_RECURSE-flag-after-recursi.patch +Patch0055: 0055-linux-user-Fixed-cpu-restore-with-pc-0-on-SIGBUS.patch +Patch0056: 0056-tcg-arm-Fix-SIGILL-in-tcg_out_qemu_st_direct.patch +Patch0057: 0057-virtio-net-correctly-copy-vnet-header-when-flushing-.patch +Patch0058: 0058-block-blklogwrites-Fix-a-bug-when-logging-write-zero.patch +Patch0059: 0059-iotests-add-filter_qmp_generated_node_ids.patch +Patch0060: 0060-iotests-port-141-to-Python-for-reliable-QMP-testing.patch +Patch0061: 0061-monitor-only-run-coroutine-commands-in-qemu_aio_cont.patch +Patch0062: 0062-qtest-bump-aspeed_smc-test-timeout-to-6-minutes.patch +Patch0063: 0063-target-xtensa-fix-OOB-TLB-entry-access.patch +Patch0064: 0064-target-arm-Fix-A64-scalar-SQSHRN-and-SQRSHRN.patch +Patch0065: 0065-target-arm-Fix-incorrect-aa64_tidcp1-feature-check.patch +Patch0066: 0066-Update-version-for-8.2.1-release.patch +Patch0067: 0067-migration-Plug-memory-leak-on-HMP-migrate-error-path.patch +Patch0068: 0068-migration-Fix-use-after-free-of-migration-state-obje.patch +Patch0069: 0069-vfio-pci-Clear-MSI-X-IRQ-index-always.patch +Patch0070: 0070-Make-uri-optional-for-migrate-QAPI.patch +Patch0071: 0071-qemu-docs-Update-options-for-graphical-frontends.patch +Patch0072: 0072-block-blkio-Make-s-mem_region_alignment-be-64-bits.patch +Patch0073: 0073-target-arm-fix-exception-syndrome-for-AArch32-bkpt-i.patch +Patch0074: 0074-system-vl.c-Fix-handling-of-serial-none-serial-somet.patch +Patch0075: 0075-qemu-options.hx-Improve-serial-option-documentation.patch +Patch0076: 0076-target-arm-Reinstate-vfp-property-on-AArch32-CPUs.patch +Patch0077: 0077-pci-host-designware-Limit-value-range-of-iATU-viewpo.patch +Patch0078: 0078-tcg-loongarch64-Set-vector-registers-call-clobbered.patch +Patch0079: 0079-hw-scsi-lsi53c895a-add-missing-decrement-of-reentran.patch +Patch0080: 0080-iotests-fix-leak-of-tmpdir-in-dry-run-mode.patch +Patch0081: 0081-iotests-give-tempdir-an-identifying-name.patch +Patch0082: 0082-virtio-scsi-Attach-event-vq-notifier-with-no_poll.patch +Patch0083: 0083-virtio-Re-enable-notifications-after-drain.patch +Patch0084: 0084-virtio-blk-avoid-using-ioeventfd-state-in-irqfd-cond.patch +Patch0085: 0085-migration-Fix-logic-of-channels-and-transport-compat.patch +Patch0086: 0086-hw-riscv-virt-acpi-build.c-fix-leak-in-build_rhct.patch +Patch0087: 0087-tests-docker-Add-sqlite3-module-to-openSUSE-Leap-con.patch +Patch0088: 0088-configure-run-plugin-TCG-tests-again.patch +Patch0089: 0089-hw-smbios-Fix-OEM-strings-table-option-validation.patch +Patch0090: 0090-hw-smbios-Fix-port-connector-option-validation.patch +Patch0091: 0091-hw-net-tulip-add-chip-status-register-values.patch +Patch0092: 0092-tcg-Increase-width-of-temp_subindex.patch +Patch0093: 0093-tcg-arm-Fix-goto_tb-for-large-translation-blocks.patch +Patch0094: 0094-vhost-user.rst-Fix-vring-address-description.patch +Patch0095: 0095-cxl-cdat-Handle-cdat-table-build-errors.patch +Patch0096: 0096-cxl-cdat-Fix-header-sum-value-in-CDAT-checksum.patch +Patch0097: 0097-hw-cxl-device-read-from-register-values-in-mdev_reg_.patch +Patch0098: 0098-hw-cxl-Pass-CXLComponentState-to-cache_mem_ops.patch +Patch0099: 0099-virtio-gpu-Correct-virgl_renderer_resource_get_info-.patch +Patch0100: 0100-virtio_iommu-Clear-IOMMUPciBus-pointer-cache-when-sy.patch +Patch0101: 0101-smmu-Clear-SMMUPciBus-pointer-cache-when-system-rese.patch +Patch0102: 0102-tests-acpi-Allow-update-of-DSDT.cxl.patch +Patch0103: 0103-hw-i386-Fix-_STA-return-value-for-ACPI0017.patch +Patch0104: 0104-linux-user-aarch64-Choose-SYNC-as-the-preferred-MTE-.patch +Patch0105: 0105-target-arm-Fix-nregs-computation-in-do_-ld-st-_zpa.patch +Patch0106: 0106-target-arm-Adjust-and-validate-mtedesc-sizem1.patch +Patch0107: 0107-target-arm-Split-out-make_svemte_desc.patch +Patch0108: 0108-target-arm-Handle-mte-in-do_ldrq-do_ldro.patch +Patch0109: 0109-target-arm-Fix-SVE-SME-gross-MTE-suppression-checks.patch +Patch0110: 0110-target-arm-Don-t-get-MDCR_EL2-in-pmu_counter_enabled.patch +Patch0111: 0111-iotests-Make-144-deterministic-again.patch +Patch0112: 0112-.gitlab-ci-windows.yml-Don-t-install-libusb-or-spice.patch +Patch0113: 0113-i386-cpu-Clear-FEAT_XSAVE_XSS_LO-HI-leafs-when-CPUID.patch +Patch0114: 0114-i386-cpu-Mask-with-XCR0-XSS-mask-for-FEAT_XSAVE_XCR0.patch +Patch0115: 0115-i386-cpuid-Decrease-cpuid_i-when-skipping-CPUID-leaf.patch +Patch0116: 0116-i386-cpuid-Move-leaf-7-to-correct-group.patch +Patch0117: 0117-target-i386-Generate-an-illegal-opcode-exception-on-.patch +Patch0118: 0118-ui-reject-extended-clipboard-message-if-not-activate.patch +Patch0119: 0119-ui-clipboard-mark-type-as-not-available-when-there-i.patch +Patch0120: 0120-ui-clipboard-add-asserts-for-update-and-request.patch +Patch0121: 0121-ui-console-Fix-console-resize-with-placeholder-surfa.patch +Patch0122: 0122-audio-Depend-on-dbus_display1_dep.patch +Patch0123: 0123-meson-Explicitly-specify-dbus-display1.h-dependency.patch +Patch0124: 0124-tests-qtest-Depend-on-dbus_display1_dep.patch +Patch0125: 0125-hw-hppa-Kconfig-Fix-building-with-configure-without-.patch +Patch0126: 0126-docs-system-Update-description-for-input-grab-key.patch +Patch0127: 0127-system-vl-Update-description-for-input-grab-key.patch +Patch0128: 0128-.gitlab-ci.d-windows.yml-Drop-msys2-32bit-job.patch +Patch0129: 0129-target-ppc-Fix-lxv-stxv-MSR-facility-check.patch +Patch0130: 0130-target-ppc-Fix-crash-on-machine-check-caused-by-ifet.patch +Patch0131: 0131-hw-nvme-fix-invalid-endian-conversion.patch +Patch0132: 0132-pl031-Update-last-RTCLR-value-on-write-in-case-it-s-.patch +Patch0133: 0133-target-i386-mask-high-bits-of-CR3-in-32-bit-mode.patch +Patch0134: 0134-target-i386-check-validity-of-VMCB-addresses.patch +Patch0135: 0135-target-i386-Fix-physical-address-truncation.patch +Patch0136: 0136-target-i386-remove-unnecessary-wrong-application-of-.patch +Patch0137: 0137-target-i386-leave-the-A20-bit-set-in-the-final-NPT-w.patch +Patch0138: 0138-tests-vm-update-openbsd-image-to-7.4.patch +Patch0139: 0139-tests-vm-avoid-re-building-the-VM-images-all-the-tim.patch +Patch0140: 0140-gitlab-force-allow-use-of-pip-in-Cirrus-jobs.patch +Patch0141: 0141-hw-intc-Kconfig-Fix-GIC-settings-when-using-without-.patch +Patch0142: 0142-hw-usb-bus.c-PCAP-adding-0xA-in-Windows-version.patch +Patch0143: 0143-tests-unit-test-util-sockets-Remove-temporary-file-a.patch +Patch0144: 0144-chardev-char-socket-Fix-TLS-io-channels-sending-too-.patch +Patch0145: 0145-Update-version-for-8.2.2-release.patch +Patch0146: 0146-target-i386-Add-new-CPU-model-SierraForest.patch +Patch0147: 0147-target-i386-Export-RFDS-bit-to-guests.patch +Patch0148: 0148-hw-loongarch-virt-Align-high-memory-base-address-wit.patch +Patch0149: 0149-target-loongarch-Add-timer-information-dump-support.patch +Patch0150: 0150-target-loongarch-meson-move-gdbstub.c-to-loongarch.s.patch +Patch0151: 0151-target-loongarch-move-translate-modules-to-tcg.patch +Patch0152: 0152-linux-headers-Update-to-Linux-v6.7-rc5.patch +Patch0153: 0153-linux-headers-Synchronize-linux-headers-from-linux-v.patch +Patch0154: 0154-target-loongarch-Define-some-kvm_arch-interfaces.patch +Patch0155: 0155-target-loongarch-Supplement-vcpu-env-initial-when-vc.patch +Patch0156: 0156-target-loongarch-Implement-kvm-get-set-registers.patch +Patch0157: 0157-target-loongarch-Implement-kvm_arch_init-function.patch +Patch0158: 0158-target-loongarch-Implement-kvm_arch_init_vcpu.patch +Patch0159: 0159-target-loongarch-Implement-kvm_arch_handle_exit.patch +Patch0160: 0160-target-loongarch-Restrict-TCG-specific-code.patch +Patch0161: 0161-target-loongarch-Implement-set-vcpu-intr-for-kvm.patch +Patch0162: 0162-target-loongarch-Add-loongarch-kvm-into-meson-build.patch +Patch0163: 0163-hw-intc-loongarch_ipi-Use-MemTxAttrs-interface-for-i.patch +Patch0164: 0164-hw-loongarch-virt-Set-iocsr-address-space-per-board-.patch +Patch0165: 0165-hw-intc-loongarch_extioi-Add-dynamic-cpu-number-supp.patch +Patch0166: 0166-hw-intc-loongarch_extioi-Add-vmstate-post_load-suppo.patch +Patch0167: 0167-configure-Add-linux-header-compile-support-for-Loong.patch +Patch0168: 0168-target-loongarch-Set-cpuid-CSR-register-only-once-wi.patch +Patch0169: 0169-target-loongarch-kvm-Enable-LSX-LASX-extension.patch +Patch0170: 0170-target-loongarch-Fix-qtest-test-hmp-error-when-KVM-o.patch +Patch0171: 0171-loongarch-Change-the-UEFI-loading-mode-to-loongarch.patch +Patch0172: 0172-target-loongarch-Fix-tlb-huge-page-loading-issue.patch +Patch0173: 0173-target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch +Patch0174: 0174-target-loongarch-kvm-Add-software-breakpoint-support.patch +Patch0175: 0175-hw-intc-loongarch_extioi-Add-virt-extension-support.patch +Patch0176: 0176-target-loongarch-kvm-sync-kernel-header-files.patch +Patch0177: 0177-hw-intc-loongarch_extioi-Add-virt-extension-support-.patch +Patch0178: 0178-target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch +Patch0179: 0179-target-loongarch-Fix-qemu-system-loongarch64-assert-.patch +Patch0180: 0180-target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch +Patch0181: 0181-target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch +Patch0182: 0182-target-i386-add-support-for-LAM-in-CPUID-enumeration.patch +Patch0183: 0183-target-i386-add-control-bits-support-for-LAM.patch +Patch0184: 0184-target-i386-Introduce-Icelake-Server-v7-to-enable-TS.patch +Patch0185: 0185-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch +Patch0186: 0186-target-i386-add-guest-phys-bits-cpu-property.patch +Patch0187: 0187-kvm-add-support-for-guest-physical-bits.patch +Patch0188: 0188-support-vpsp.patch +Patch0189: 0189-doc-update-AMD-SEV-to-include-Live-migration-flow.patch +Patch0190: 0190-migration.json-add-AMD-SEV-specific-migration-parame.patch +Patch0191: 0191-confidential-guest-support-introduce-ConfidentialGue.patch +Patch0192: 0192-target-i386-sev-provide-callback-to-setup-outgoing-c.patch +Patch0193: 0193-target-i386-sev-do-not-create-launch-context-for-an-.patch +Patch0194: 0194-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch +Patch0195: 0195-target-i386-sev-add-support-to-load-incoming-encrypt.patch +Patch0196: 0196-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch +Patch0197: 0197-migration-add-support-to-migrate-shared-regions-list.patch +Patch0198: 0198-migration-ram-add-support-to-send-encrypted-pages.patch +Patch0199: 0199-migration-ram-Force-encrypted-status-for-flash0-flas.patch +Patch0200: 0200-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch +Patch0201: 0201-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch +Patch0202: 0202-migration-ram-Force-encrypted-status-for-VGA-vram.patch +Patch0203: 0203-target-i386-sev-Clear-shared_regions_list-when-reboo.patch +Patch0204: 0204-migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch +Patch0205: 0205-target-i386-Introduce-header-file-csv.h.patch +Patch0206: 0206-target-i386-csv-Read-cert-chain-from-file-when-prepa.patch +Patch0207: 0207-target-i386-csv-add-support-to-queue-the-outgoing-pa.patch +Patch0208: 0208-target-i386-csv-add-support-to-encrypt-the-outgoing-.patch +Patch0209: 0209-target-i386-csv-add-support-to-queue-the-incoming-pa.patch +Patch0210: 0210-target-i386-csv-add-support-to-load-incoming-encrypt.patch +Patch0211: 0211-migration-ram-Accelerate-the-transmission-of-CSV-gue.patch +Patch0212: 0212-migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch +Patch0213: 0213-target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch +Patch0214: 0214-target-i386-get-set-migrate-GHCB-state.patch +Patch0215: 0215-target-i386-kvm-Fix-the-resettable-info-when-emulate.patch +Patch0216: 0216-kvm-Add-support-for-CSV2-reboot.patch +Patch0217: 0217-target-i386-csv-Add-CSV3-context.patch +Patch0218: 0218-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch +Patch0219: 0219-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch +Patch0220: 0220-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch +Patch0221: 0221-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch +Patch0222: 0222-target-i386-csv-Do-not-register-unregister-guest-sec.patch +Patch0223: 0223-target-i386-csv-Load-initial-image-to-private-memory.patch +Patch0224: 0224-vga-Force-full-update-for-CSV3-guest.patch +Patch0225: 0225-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch +Patch0226: 0226-linux-headers-update-kernel-headers-to-include-CSV3-.patch +Patch0227: 0227-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch +Patch0228: 0228-target-i386-csv-Add-support-to-migrate-the-incoming-.patch +Patch0229: 0229-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch +Patch0230: 0230-target-i386-csv-Add-support-to-migrate-the-incoming-.patch +Patch0231: 0231-target-i386-sev-Fix-incompatibility-between-SEV-and-.patch +Patch0232: 0232-target-i386-sev-Add-support-for-reuse-ASID-for-diffe.patch +Patch0233: 0233-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch +Patch0234: 0234-target-i386-Add-new-Hygon-Dharma-CPU-model.patch +Patch0235: 0235-vfio-Add-vfio-based-mediated-hct-support.patch +Patch0236: 0236-hw-net-virtio-net-Update-event-idx-if-guest-has-made.patch +Patch0237: 0237-target-i386-csv-Release-CSV3-shared-pages-after-unma.patch +Patch0238: 0238-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch +Patch0239: 0239-devel-8.2-Hygon-HCT-Fix-for-vfio-based-mediated-hct.patch +Patch0240: 0240-update-to-qemu-9.1-with-directory-hw-loongarch.patch +Patch0241: 0241-target-loongarch-Support-QMP-dump-guest-memory.patch +Patch0242: 0242-target-loongarch-Add-compatible-support-about-VM-reb.patch +Patch0243: 0243-target-loongarch-kvm-Add-vCPU-reset-function.patch +Patch0244: 0244-acpi-ged-Add-macro-for-acpi-sleep-control-register.patch +Patch0245: 0245-hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch +Patch0246: 0246-target-loongarch-Avoid-bits-shift-exceeding-width-of.patch +Patch0247: 0247-target-loongarch-Add-loongson-binary-translation-fea.patch +Patch0248: 0248-target-loongarch-Implement-lbt-registers-save-restor.patch +Patch0249: 0249-target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch +Patch0250: 0250-linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch +Patch0251: 0251-target-loongarch-Add-steal-time-support-on-migration.patch +Patch0252: 0252-sync-kernel-headers.patch +Patch0253: 0253-accel-kvm-Extract-common-KVM-vCPU-creation-parking-c.patch +Patch0254: 0254-hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c.patch +Patch0255: 0255-hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho.patch +Patch0256: 0256-hw-acpi-Update-GED-_EVT-method-AML-with-CPU-scan.patch +Patch0257: 0257-hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change.patch +Patch0258: 0258-physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch +Patch0259: 0259-gdbstub-Add-helper-function-to-unregister-GDB-regist.patch +Patch0260: 0260-accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch +Patch0261: 0261-hw-loongarch-virt-Add-CPU-topology-support.patch +Patch0262: 0262-Add-basic-CPU-plug-support.patch +Patch0263: 0263-hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch +Patch0264: 0264-hw-loongarch-Add-KVM-IPI-device-support.patch +Patch0265: 0265-hw-loongarch-Add-KVM-extioi-device-support.patch +Patch0266: 0266-hw-loongarch-Add-KVM-pch-pic-device-support.patch +Patch0267: 0267-hw-loongarch-Add-KVM-pch-msi-device-support.patch +Patch0268: 0268-target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch +Patch0269: 0269-target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch +Patch0270: 0270-target-loongarch-fixed-a-multi-core-boot-issue.patch +Patch0271: 0271-hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch +Patch0272: 0272-target-loongarch-fix-Werror-maybe-uninitialized-fals.patch +Patch0273: 0273-target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch +Patch0274: 0274-target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch +Patch0275: 0275-target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch +Patch0276: 0276-target-loongarch-fix-a-wrong-print-in-cpu-dump.patch +Patch0277: 0277-loongarch-switch-boards-to-default-y.patch +Patch0278: 0278-tests-libqos-Add-loongarch-virt-machine-node.patch +Patch0279: 0279-target-loongarch-kvm-Add-software-breakpoint-support.patch +Patch0280: 0280-enable-the-irqchip-simulation-function.patch +Patch0281: 0281-hw-i386-pc-add-mem2-option-for-qemu.patch +Patch0282: 0282-hw-misc-psp-support-tkm-use-mem2-memory.patch +Patch0283: 0283-hw-misc-psp-Pin-the-hugepage-memory-specified-by-mem.patch +Patch0284: 0284-fix-potential-use-after-free-with-dbus-shared-memory.patch +#https://gitlab.com/qemu-project/qemu/-/commit/98e77e3dd8dd6e7aa9a7dffa60f49c8c8a49d4e3 +Patch0285: 0285-fix-CVE-2024-7730.patch ExclusiveArch: x86_64 aarch64 loongarch64 @@ -496,16 +711,23 @@ BuildRequires: glibc-static pcre-static glib2-static zlib-static %endif Requires: %{name}-user = %{EVR} +%ifarch aarch64 Requires: %{name}-system-aarch64 = %{EVR} -Requires: %{name}-system-arm = %{EVR} +%endif +%ifarch loongarch64 Requires: %{name}-system-loongarch64 = %{EVR} +%endif +%ifarch riscv Requires: %{name}-system-riscv = %{EVR} +%endif +%ifarch x86_64 Requires: %{name}-system-x86 = %{EVR} +%endif Requires: %{name}-img = %{EVR} Requires: %{name}-tools = %{EVR} Requires: qemu-pr-helper = %{EVR} -# Begin with Anolis 23, qemu-kvm was changed to a meta package rather than +# Begin with Anolis 23, qemu-kvm was changed to a meta package rather than # a package containing actual files. So conflicting with older distro. Conflicts: (qemu-kvm < %{EVR} and anolis-release < 23) @@ -802,6 +1024,8 @@ Obsoletes: qemu-kvm-device-display-virtio-gpu-ccw < %{EVR} %description device-display-virtio-gpu-ccw This package provides the virtio-gpu-ccw display device for QEMU. +# virtio-vga only support legacy firmware.Aarch64 cannot support. +%ifnarch aarch64 loongarch64 %package device-display-virtio-vga Summary: QEMU virtio-vga display device Requires: %{name}-common = %{EVR} @@ -815,6 +1039,7 @@ Requires: %{name}-common = %{EVR} Obsoletes: qemu-kvm-device-display-virtio-vga-gl < %{EVR} %description device-display-virtio-vga-gl This package provides the virtio-vga-gl display device for QEMU. +%endif %package device-usb-host Summary: QEMU usb host device @@ -864,6 +1089,8 @@ Obsoletes: qemu-kvm-ui-spice-app < %{EVR} %description ui-spice-app This package provides the additional spice-app UI for QEMU. +# qxl is a vga compatible device which only legacy firmware need +%ifnarch aarch64 loongarch64 %package device-display-qxl Summary: QEMU QXL display device Requires: %{name}-common = %{EVR} @@ -871,6 +1098,7 @@ Requires: %{name}-ui-spice-core = %{EVR} Obsoletes: qemu-kvm-device-display-qxl < %{EVR} %description device-display-qxl This package provides the QXL display device for QEMU. +%endif %package char-spice Summary: QEMU spice chardev driver @@ -938,6 +1166,7 @@ static binaries %endif +%ifarch aarch64 %package system-aarch64 Summary: QEMU system emulator for AArch64 Requires: %{name}-system-aarch64-core = %{EVR} @@ -954,29 +1183,17 @@ Requires: edk2-aarch64 %description system-aarch64-core This package provides the QEMU system emulator for AArch64. -%package system-arm -Summary: QEMU system emulator for ARM -Requires: %{name}-system-arm-core = %{EVR} -%{requires_all_modules} -%description system-arm -This package provides the QEMU system emulator for ARM systems. - -%package system-arm-core -Summary: QEMU system emulator for ARM -Requires: %{name}-common = %{EVR} -%description system-arm-core -This package provides the QEMU system emulator for ARM boards. - +%endif +%ifarch loongarch64 %package system-loongarch64 Summary: QEMU system emulator for LoongArch (LA64) Requires: %{name}-system-loongarch64-core = %{EVR} %{requires_all_modules} %description system-loongarch64 This package provides the QEMU system emulator for Loongson boards. - + %package system-loongarch64-core -Requires: seavgabios-bin %if %{have_edk2} Requires: edk2-loongarch64 %endif @@ -984,8 +1201,9 @@ Summary: QEMU system emulator for LoongArch (LA64) Requires: %{name}-common = %{EVR} %description system-loongarch64-core This package provides the QEMU system emulator for Loongson boards. +%endif - +%ifarch riscv %package system-riscv Summary: QEMU system emulator for RISC-V Requires: %{name}-system-riscv-core = %{EVR} @@ -998,8 +1216,10 @@ Summary: QEMU system emulator for RISC-V Requires: %{name}-common = %{EVR} %description system-riscv-core This package provides the QEMU system emulator for RISC-V systems. +%endif +%ifarch x86_64 %package system-x86 Summary: QEMU system emulator for x86 Requires: %{name}-system-x86-core = %{EVR} @@ -1022,6 +1242,7 @@ Requires: edk2-ovmf This package provides the QEMU system emulator for x86. When being run in a x86 machine that supports it, this package also provides the KVM virtualization platform. +%endif %prep @@ -1123,7 +1344,6 @@ mkdir -p %{static_builddir} --disable-spice \\\ --disable-spice-protocol \\\ --disable-strip \\\ - --disable-system \\\ --disable-tcg \\\ --disable-tools \\\ --disable-tpm \\\ @@ -1248,7 +1468,6 @@ run_configure \ --enable-slirp \ --enable-slirp-smbd \ --enable-snappy \ - --enable-system \ --enable-tcg \ --enable-tools \ --enable-tpm \ @@ -1269,7 +1488,9 @@ run_configure \ \ \ --audio-drv-list=pa,alsa,%{?jack_drv}oss \ + %if 0%{?all_system_emu_support} == 1 --target-list-exclude=moxie-softmmu \ + %endif --with-default-devices \ --enable-auth-pam \ --enable-bochs \ @@ -1298,7 +1519,6 @@ run_configure \ %if %{have_librdma} --enable-pvrdma \ %endif - --enable-qcow1 \ --enable-qed \ --enable-qom-cast-debug \ --enable-replication \ @@ -1473,8 +1693,10 @@ rm -rf %{buildroot}%{qemudocdir}/specs # Provided by package ipxe rm -rf %{buildroot}%{_datadir}/%{name}/pxe*rom rm -rf %{buildroot}%{_datadir}/%{name}/efi*rom +%ifnarch loongarch64 # Provided by package seavgabios rm -rf %{buildroot}%{_datadir}/%{name}/vgabios*bin +%endif # Provided by package seabios rm -rf %{buildroot}%{_datadir}/%{name}/bios*.bin # Provided by package sgabios @@ -1494,6 +1716,9 @@ rm -f %{buildroot}/%{_datadir}/systemtap/tapset/qemu-system-{alpha,avr,cris,hppa # remove unused header files rm -f %{buildroot}%{_includedir}/qemu-plugin.h +%ifarch aarch64 loongarch64 +rm -f %{buildroot}%{_libdir}/%{name}/hw-display-qxl.so +%endif # Fedora specific stuff below %find_lang %{name} @@ -1674,12 +1899,33 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %endif %config(noreplace) %{_sysconfdir}/sasl2/%{name}.conf - %{_datadir}/applications/qemu.desktop %exclude %{_datadir}/%{name}/qemu-nsis.bmp %{_libexecdir}/virtfs-proxy-helper %{_mandir}/man1/virtfs-proxy-helper.1* +%{_datadir}/%{name}/npcm7xx_bootrom.bin +%{_datadir}/%{name}/opensbi-*.bin +%{_datadir}/%{name}/kvmvapic.bin +%{_datadir}/%{name}/linuxboot.bin +%{_datadir}/%{name}/multiboot.bin +%{_datadir}/%{name}/multiboot_dma.bin +%{_datadir}/%{name}/pvh.bin +%{_datadir}/%{name}/qboot.rom + +%ifarch loongarch64 +# Provided by package seavgabios +%{_datadir}/%{name}/vgabios-ati.bin +%{_datadir}/%{name}/vgabios-bochs-display.bin +%{_datadir}/%{name}/vgabios-cirrus.bin +%{_datadir}/%{name}/vgabios-qxl.bin +%{_datadir}/%{name}/vgabios-ramfb.bin +%{_datadir}/%{name}/vgabios-stdvga.bin +%{_datadir}/%{name}/vgabios-virtio.bin +%{_datadir}/%{name}/vgabios-vmware.bin +%{_datadir}/%{name}/vgabios.bin +%endif + %files tests %{testsdir} @@ -1754,10 +2000,12 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %endif %files device-display-virtio-gpu-ccw %{_libdir}/%{name}/hw-s390x-virtio-gpu-ccw.so +%ifnarch aarch64 loongarch64 %files device-display-virtio-vga %{_libdir}/%{name}/hw-display-virtio-vga.so %files device-display-virtio-vga-gl %{_libdir}/%{name}/hw-display-virtio-vga-gl.so +%endif %files device-usb-host %{_libdir}/%{name}/hw-usb-host.so %files device-usb-redirect @@ -1777,8 +2025,10 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %{_libdir}/%{name}/audio-spice.so %files char-spice %{_libdir}/%{name}/chardev-spice.so +%ifnarch aarch64 loongarch64 %files device-display-qxl %{_libdir}/%{name}/hw-display-qxl.so +%endif %files ui-spice-core %{_libdir}/%{name}/ui-spice-core.so %files ui-spice-app @@ -1796,63 +2046,19 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %files user -%{_bindir}/qemu-i386 +%ifarch x86_64 %{_bindir}/qemu-x86_64 +%{_datadir}/systemtap/tapset/qemu-x86_64*.stp +%endif +%ifarch aarch64 %{_bindir}/qemu-aarch64 %{_bindir}/qemu-aarch64_be -%{_bindir}/qemu-alpha -%{_bindir}/qemu-arm -%{_bindir}/qemu-armeb -%{_bindir}/qemu-cris -%{_bindir}/qemu-hppa -%{_bindir}/qemu-hexagon -%{_bindir}/qemu-loongarch64 -%{_bindir}/qemu-m68k -%{_bindir}/qemu-microblaze -%{_bindir}/qemu-microblazeel -%{_bindir}/qemu-mips -%{_bindir}/qemu-mipsel -%{_bindir}/qemu-mips64 -%{_bindir}/qemu-mips64el -%{_bindir}/qemu-mipsn32 -%{_bindir}/qemu-mipsn32el -%{_bindir}/qemu-nios2 -%{_bindir}/qemu-or1k -%{_bindir}/qemu-ppc -%{_bindir}/qemu-ppc64 -%{_bindir}/qemu-ppc64le -%{_bindir}/qemu-riscv32 -%{_bindir}/qemu-riscv64 -%{_bindir}/qemu-s390x -%{_bindir}/qemu-sh4 -%{_bindir}/qemu-sh4eb -%{_bindir}/qemu-sparc -%{_bindir}/qemu-sparc32plus -%{_bindir}/qemu-sparc64 -%{_bindir}/qemu-xtensa -%{_bindir}/qemu-xtensaeb - -%{_datadir}/systemtap/tapset/qemu-i386*.stp -%{_datadir}/systemtap/tapset/qemu-x86_64*.stp %{_datadir}/systemtap/tapset/qemu-aarch64*.stp -%{_datadir}/systemtap/tapset/qemu-alpha*.stp -%{_datadir}/systemtap/tapset/qemu-arm*.stp -%{_datadir}/systemtap/tapset/qemu-cris*.stp -%{_datadir}/systemtap/tapset/qemu-hppa*.stp -%{_datadir}/systemtap/tapset/qemu-hexagon*.stp +%endif +%ifarch loongarch64 +%{_bindir}/qemu-loongarch64 %{_datadir}/systemtap/tapset/qemu-loongarch64*.stp -%{_datadir}/systemtap/tapset/qemu-m68k*.stp -%{_datadir}/systemtap/tapset/qemu-microblaze*.stp -%{_datadir}/systemtap/tapset/qemu-mips*.stp -%{_datadir}/systemtap/tapset/qemu-nios2*.stp -%{_datadir}/systemtap/tapset/qemu-or1k*.stp -%{_datadir}/systemtap/tapset/qemu-ppc*.stp -%{_datadir}/systemtap/tapset/qemu-riscv*.stp -%{_datadir}/systemtap/tapset/qemu-s390x*.stp -%{_datadir}/systemtap/tapset/qemu-sh4*.stp -%{_datadir}/systemtap/tapset/qemu-sparc*.stp -%{_datadir}/systemtap/tapset/qemu-xtensa*.stp - +%endif %files user-binfmt %{_exec_prefix}/lib/binfmt.d/qemu-*-dynamic.conf @@ -1864,26 +2070,23 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %{_datadir}/systemtap/tapset/qemu-*-static.stp %endif - +%ifarch aarch64 %files system-aarch64 %files system-aarch64-core %{_bindir}/qemu-system-aarch64 %{_datadir}/systemtap/tapset/qemu-system-aarch64*.stp %{_mandir}/man1/qemu-system-aarch64.1* +%endif -%files system-arm -%files system-arm-core -%{_bindir}/qemu-system-arm -%{_datadir}/%{name}/npcm7xx_bootrom.bin -%{_datadir}/systemtap/tapset/qemu-system-arm*.stp -%{_mandir}/man1/qemu-system-arm.1* - +%ifarch loongarch64 %files system-loongarch64 %files system-loongarch64-core %{_bindir}/qemu-system-loongarch64 %{_datadir}/systemtap/tapset/qemu-system-loongarch64*.stp %{_mandir}/man1/qemu-system-loongarch64.1* +%endif +%ifarch riscv %files system-riscv %files system-riscv-core %{_bindir}/qemu-system-riscv32 @@ -1891,32 +2094,65 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %{_datadir}/%{name}/opensbi-riscv*.bin %{_datadir}/systemtap/tapset/qemu-system-riscv*.stp %{_mandir}/man1/qemu-system-riscv*.1* +%endif +%ifarch x86_64 %files system-x86 %files system-x86-core -%{_bindir}/qemu-system-i386 %{_bindir}/qemu-system-x86_64 -%{_libdir}/%{name}/accel-tcg-i386.so %{_libdir}/%{name}/accel-tcg-x86_64.so -%{_datadir}/systemtap/tapset/qemu-system-i386*.stp %{_datadir}/systemtap/tapset/qemu-system-x86_64*.stp -%{_mandir}/man1/qemu-system-i386.1* %{_mandir}/man1/qemu-system-x86_64.1* -%{_datadir}/%{name}/kvmvapic.bin -%{_datadir}/%{name}/linuxboot.bin -%{_datadir}/%{name}/multiboot.bin -%{_datadir}/%{name}/multiboot_dma.bin -%{_datadir}/%{name}/pvh.bin -%{_datadir}/%{name}/qboot.rom %if %{need_qemu_kvm} %{_bindir}/qemu-kvm %{_mandir}/man1/qemu-kvm.1* %endif +%endif # endif !tools_only %endif %changelog +* Fri Dec 13 2024 yangxinyu - 2:8.2.0-26 +- fix CVE-2024-7730 + +* Sat Nov 30 2024 Xianglai Li - 2:8.2.0-25 +- Remove loongarch qemu's dependency on the seavgabios package. + +* Wed Nov 27 2024 Xianglai Li - 2:8.2.0-24 +- Enable spice for loongarch64. + +* Wed Nov 27 2024 mgb01105731 - 2:8.2.0-23 +- Fix vm cannot boot on arm64 plateform + +* Mon Nov 15 2024 Chang Gao - 2:8.2.0-22 +- Disable other platform support when running on specified arch. + +* Tue Nov 14 2024 Xuchun Shang - 2:8.2.0-21 +- Update the src package and release for version 21 + +* Tue Oct 29 2024 Xuchun Shang - 2:8.2.0-20 +- Update the src package and release for version 20 + +* Thu Sep 26 2024 Wenlong Zhang - 2:8.2.0-19 +- enable block_rbd for loongarch64 + +* Sun Aug 18 2024 Wencheng Yang - 2:8.2.0-18 +- Patch1054: 1054-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch + (Fix network stall at the host side waiting for kick) + +* Mon Jun 20 2024 Wencheng Yang - 2:8.2.0-17 +- Patch1053: 1053-target-i386-csv-Release-CSV3-shared-pages-after-unma.patch + (Release CSV3 shared pages after unmapping DMA) + +* Mon Jun 17 2024 Wencheng Yang - 2:8.2.0-16 +- Patch1052: 1052-hw-net-virtio-net-Update-event-idx-if-guest-has-made.patch + (Update virtio-net event idx after double check) + +* Fri Jun 7 2024 Depei Yang -2.8.2.0-15 +- Patch1051: 1051-vfio-Add-vfio-based-mediated-hct-support.patch + (Add HCT support for hygon platform) + * Wed May 22 2024 Song Gao -2.8.2.0-14 - Patch0036: 0036-target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch - Patch0037: 0037-target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch @@ -2043,7 +2279,7 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ * Wed Mar 20 2024 Jacob Wang - 2:8.2.0-1 - Update to 8.2.0 - Remove subpackage of virtiofsd since QEMU upstream deleted the C impl of + Remove subpackage of virtiofsd since QEMU upstream deleted the C impl of virtiofsd entirely. The alternative is to rewrite it separately in rust. * Sat Mar 06 2024 Liyang Han - 15:7.2.6-8