aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--Makefile6
-rw-r--r--backends/cryptodev-lkcf.c3
-rw-r--r--bsd-user/elfload.c6
-rw-r--r--configs/devices/i386-softmmu/default.mak1
-rw-r--r--docs/interop/firmware.json12
-rw-r--r--docs/system/devices/net.rst100
-rw-r--r--docs/system/loongarch/virt.rst31
-rw-r--r--docs/system/target-loongarch.rst19
-rw-r--r--docs/system/targets.rst1
-rw-r--r--host/include/loongarch64/host/atomic128-ldst.h.inc4
-rw-r--r--host/include/loongarch64/host/bufferiszero.c.inc6
-rw-r--r--host/include/loongarch64/host/load-extract-al16-al8.h.inc2
-rw-r--r--hw/arm/Kconfig30
-rw-r--r--hw/char/Kconfig6
-rw-r--r--hw/char/meson.build2
-rw-r--r--hw/core/loader.c4
-rw-r--r--hw/core/qdev-properties.c37
-rw-r--r--hw/i386/fw_cfg.c2
-rw-r--r--hw/i386/pc.c2
-rw-r--r--hw/intc/xive.c29
-rw-r--r--hw/intc/xive2.c21
-rw-r--r--hw/loongarch/virt.c41
-rw-r--r--hw/ppc/amigaone.c16
-rw-r--r--hw/ppc/mac_newworld.c7
-rw-r--r--hw/ppc/mac_oldworld.c7
-rw-r--r--hw/ppc/pnv.c2
-rw-r--r--hw/ppc/pnv_bmc.c4
-rw-r--r--hw/ppc/pnv_core.c6
-rw-r--r--hw/ppc/pnv_occ.c201
-rw-r--r--hw/ppc/pnv_pnor.c2
-rw-r--r--hw/ppc/spapr.c2
-rw-r--r--hw/ppc/spapr_cpu_core.c6
-rw-r--r--hw/ppc/spapr_rtas.c5
-rw-r--r--hw/riscv/virt.c2
-rw-r--r--hw/sparc/sun4m.c9
-rw-r--r--hw/sparc64/sun4u.c9
-rw-r--r--hw/timer/Kconfig8
-rw-r--r--hw/timer/meson.build2
-rw-r--r--hw/uefi/Kconfig2
-rw-r--r--hw/uefi/var-service-core.c1
-rw-r--r--hw/uefi/var-service-json.c24
-rw-r--r--hw/xen/xen-bus.c8
-rw-r--r--include/exec/cpu-all.h12
-rw-r--r--include/exec/poison.h1
-rw-r--r--include/hw/char/pl011.h5
-rw-r--r--include/hw/loader.h2
-rw-r--r--include/hw/ppc/pnv_pnor.h1
-rw-r--r--include/hw/qdev-properties.h1
-rw-r--r--linux-user/elfload.c8
-rw-r--r--linux-user/syscall_defs.h2
-rw-r--r--net/vmnet-common.m2
-rw-r--r--rust/hw/char/pl011/src/device.rs9
-rw-r--r--rust/hw/char/pl011/src/device_class.rs8
-rw-r--r--rust/hw/timer/Kconfig1
-rw-r--r--rust/hw/timer/hpet/src/hpet.rs8
-rw-r--r--rust/qemu-api/meson.build5
-rw-r--r--rust/qemu-api/src/assertions.rs37
-rw-r--r--rust/qemu-api/src/vmstate.rs100
-rw-r--r--rust/qemu-api/tests/tests.rs2
-rw-r--r--rust/qemu-api/tests/vmstate_tests.rs477
-rw-r--r--rust/wrapper.h1
-rw-r--r--target/loongarch/internals.h2
-rw-r--r--target/loongarch/kvm/kvm.c8
-rw-r--r--target/loongarch/tcg/csr_helper.c2
-rw-r--r--target/loongarch/tcg/tlb_helper.c15
-rw-r--r--target/ppc/cpu.h11
-rw-r--r--target/ppc/cpu_init.c8
-rw-r--r--target/ppc/excp_helper.c4
-rw-r--r--target/ppc/translate/vmx-impl.c.inc2
-rw-r--r--target/ppc/translate/vsx-impl.c.inc20
-rw-r--r--tests/qtest/meson.build3
72 files changed, 1114 insertions, 332 deletions
diff --git a/.mailmap b/.mailmap
index 5f6df41..33fe754 100644
--- a/.mailmap
+++ b/.mailmap
@@ -67,6 +67,7 @@ Andrey Drobyshev <andrey.drobyshev@virtuozzo.com> Andrey Drobyshev via <qemu-blo
BALATON Zoltan <balaton@eik.bme.hu> BALATON Zoltan via <qemu-ppc@nongnu.org>
# Next, replace old addresses by a more recent one.
+Akihiko Odaki <akihiko.odaki@daynix.com> <akihiko.odaki@gmail.com>
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@mips.com>
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@imgtec.com>
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <amarkovic@wavecomp.com>
diff --git a/Makefile b/Makefile
index b65b0bd..c92a3cf 100644
--- a/Makefile
+++ b/Makefile
@@ -207,10 +207,10 @@ clean: recurse-clean
VERSION = $(shell cat $(SRC_PATH)/VERSION)
-dist: qemu-$(VERSION).tar.bz2
+dist: qemu-$(VERSION).tar.xz
-qemu-%.tar.bz2:
- $(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)"
+qemu-%.tar.xz:
+ $(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.xz,%,$@)"
distclean: clean recurse-distclean
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || :
diff --git a/backends/cryptodev-lkcf.c b/backends/cryptodev-lkcf.c
index 41cf24b..352c3e8 100644
--- a/backends/cryptodev-lkcf.c
+++ b/backends/cryptodev-lkcf.c
@@ -330,6 +330,8 @@ static void cryptodev_lkcf_execute_task(CryptoDevLKCFTask *task)
cryptodev_lkcf_set_op_desc(&session->akcipher_opts, op_desc,
sizeof(op_desc), &local_error) != 0) {
error_report_err(local_error);
+ status = -VIRTIO_CRYPTO_ERR;
+ goto out;
} else {
key_id = add_key(KCTL_KEY_TYPE_PKEY, "lkcf-backend-priv-key",
p8info, p8info_len, KCTL_KEY_RING);
@@ -346,6 +348,7 @@ static void cryptodev_lkcf_execute_task(CryptoDevLKCFTask *task)
session->key, session->keylen,
&local_error);
if (!akcipher) {
+ error_report_err(local_error);
status = -VIRTIO_CRYPTO_ERR;
goto out;
}
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 833fa3b..3bca0cc 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -44,7 +44,7 @@ static inline void memcpy_fromfs(void *to, const void *from, unsigned long n)
memcpy(to, from, n);
}
-#ifdef BSWAP_NEEDED
+#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
static void bswap_ehdr(struct elfhdr *ehdr)
{
bswap16s(&ehdr->e_type); /* Object file type */
@@ -111,7 +111,7 @@ static void bswap_note(struct elf_note *en)
bswap32s(&en->n_type);
}
-#else /* ! BSWAP_NEEDED */
+#else
static void bswap_ehdr(struct elfhdr *ehdr) { }
static void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
@@ -119,7 +119,7 @@ static void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
static void bswap_sym(struct elf_sym *sym) { }
static void bswap_note(struct elf_note *en) { }
-#endif /* ! BSWAP_NEEDED */
+#endif /* HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN */
#include "elfcore.c"
diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak
index 9ef343c..4faf2f0 100644
--- a/configs/devices/i386-softmmu/default.mak
+++ b/configs/devices/i386-softmmu/default.mak
@@ -6,7 +6,6 @@
#CONFIG_APPLESMC=n
#CONFIG_FDC=n
#CONFIG_HPET=n
-#CONFIG_X_HPET_RUST=n
#CONFIG_HYPERV=n
#CONFIG_ISA_DEBUG=n
#CONFIG_ISA_IPMI_BT=n
diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json
index 57f55f6..745d21d 100644
--- a/docs/interop/firmware.json
+++ b/docs/interop/firmware.json
@@ -214,13 +214,23 @@
# PL011 UART. @verbose-static is mutually exclusive
# with @verbose-dynamic.
#
+# @host-uefi-vars: The firmware expects the host to provide an uefi
+# variable store. qemu supports that via
+# "uefi-vars-sysbus" (aarch64, riscv64, loongarch64)
+# or "uefi-vars-x64" (x86_64) devices. The firmware
+# will not use flash for nvram. When loading the
+# firmware into flash the 'stateless' setup should be
+# used. It is recommened to load the firmware into
+# memory though.
+#
# Since: 3.0
##
{ 'enum' : 'FirmwareFeature',
'data' : [ 'acpi-s3', 'acpi-s4',
'amd-sev', 'amd-sev-es', 'amd-sev-snp',
'intel-tdx',
- 'enrolled-keys', 'requires-smm', 'secure-boot',
+ 'enrolled-keys', 'requires-smm',
+ 'secure-boot', 'host-uefi-vars',
'verbose-dynamic', 'verbose-static' ] }
##
diff --git a/docs/system/devices/net.rst b/docs/system/devices/net.rst
index 2ab516d..a3efbdc 100644
--- a/docs/system/devices/net.rst
+++ b/docs/system/devices/net.rst
@@ -77,6 +77,106 @@ When using the ``'-netdev user,hostfwd=...'`` option, TCP or UDP
connections can be redirected from the host to the guest. It allows for
example to redirect X11, telnet or SSH connections.
+Using passt as the user mode network stack
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+passt_ can be used as a simple replacement for SLIRP (``-net user``).
+passt doesn't require any capability or privilege. passt has
+better performance than ``-net user``, full IPv6 support and better security
+as it's a daemon that is not executed in QEMU context.
+
+passt can be connected to QEMU either by using a socket
+(``-netdev stream``) or using the vhost-user interface (``-netdev vhost-user``).
+See `passt(1)`_ for more details on passt.
+
+.. _passt: https://passt.top/
+.. _passt(1): https://passt.top/builds/latest/web/passt.1.html
+
+To use socket based passt interface:
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Start passt as a daemon::
+
+ passt --socket ~/passt.socket
+
+If ``--socket`` is not provided, passt will print the path of the UNIX domain socket QEMU can connect to (``/tmp/passt_1.socket``, ``/tmp/passt_2.socket``,
+...). Then you can connect your QEMU instance to passt:
+
+.. parsed-literal::
+ |qemu_system| [...OPTIONS...] -device virtio-net-pci,netdev=netdev0 -netdev stream,id=netdev0,server=off,addr.type=unix,addr.path=~/passt.socket
+
+Where ``~/passt.socket`` is the UNIX socket created by passt to
+communicate with QEMU.
+
+To use vhost-based interface:
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Start passt with ``--vhost-user``::
+
+ passt --vhost-user --socket ~/passt.socket
+
+Then to connect QEMU:
+
+.. parsed-literal::
+ |qemu_system| [...OPTIONS...] -m $RAMSIZE -chardev socket,id=chr0,path=~/passt.socket -netdev vhost-user,id=netdev0,chardev=chr0 -device virtio-net,netdev=netdev0 -object memory-backend-memfd,id=memfd0,share=on,size=$RAMSIZE -numa node,memdev=memfd0
+
+Where ``$RAMSIZE`` is the memory size of your VM ``-m`` and ``-object memory-backend-memfd,size=`` must match.
+
+Migration of passt:
+^^^^^^^^^^^^^^^^^^^
+
+When passt is connected to QEMU using the vhost-user interface it can
+be migrated with QEMU and the network connections are not interrupted.
+
+As passt runs with no privileges, it relies on passt-repair to save and
+load the TCP connections state, using the TCP_REPAIR socket option.
+The passt-repair helper needs to have the CAP_NET_ADMIN capability, or run as root. If passt-repair is not available, TCP connections will not be preserved.
+
+Example of migration of a guest on the same host
+________________________________________________
+
+Before being able to run passt-repair, the CAP_NET_ADMIN capability must be set
+on the file, run as root::
+
+ setcap cap_net_admin+eip ./passt-repair
+
+Start passt for the source side::
+
+ passt --vhost-user --socket ~/passt_src.socket --repair-path ~/passt-repair_src.socket
+
+Where ``~/passt-repair_src.socket`` is the UNIX socket created by passt to
+communicate with passt-repair. The default value is the ``--socket`` path
+appended with ``.repair``.
+
+Start passt-repair::
+
+ passt-repair ~/passt-repair_src.socket
+
+Start source side QEMU with a monitor to be able to send the migrate command:
+
+.. parsed-literal::
+ |qemu_system| [...OPTIONS...] [...VHOST USER OPTIONS...] -monitor stdio
+
+Start passt for the destination side::
+
+ passt --vhost-user --socket ~/passt_dst.socket --repair-path ~/passt-repair_dst.socket
+
+Start passt-repair::
+
+ passt-repair ~/passt-repair_dst.socket
+
+Start QEMU with the ``-incoming`` parameter:
+
+.. parsed-literal::
+ |qemu_system| [...OPTIONS...] [...VHOST USER OPTIONS...] -incoming tcp:localhost:4444
+
+Then in the source guest monitor the migration can be started::
+
+ (qemu) migrate tcp:localhost:4444
+
+A separate passt-repair instance must be started for every migration. In the case of a failed migration, passt-repair also needs to be restarted before trying
+again.
+
Hubs
~~~~
diff --git a/docs/system/loongarch/virt.rst b/docs/system/loongarch/virt.rst
index 172fba0..7845878 100644
--- a/docs/system/loongarch/virt.rst
+++ b/docs/system/loongarch/virt.rst
@@ -12,14 +12,15 @@ Supported devices
-----------------
The ``virt`` machine supports:
-- Gpex host bridge
-- Ls7a RTC device
-- Ls7a IOAPIC device
-- ACPI GED device
-- Fw_cfg device
-- PCI/PCIe devices
-- Memory device
-- CPU device. Type: la464.
+
+* Gpex host bridge
+* Ls7a RTC device
+* Ls7a IOAPIC device
+* ACPI GED device
+* Fw_cfg device
+* PCI/PCIe devices
+* Memory device
+* CPU device. Type: la464.
CPU and machine Type
--------------------
@@ -39,13 +40,7 @@ can be accessed by following steps.
.. code-block:: bash
- ./configure --disable-rdma --prefix=/usr \
- --target-list="loongarch64-softmmu" \
- --disable-libiscsi --disable-libnfs --disable-libpmem \
- --disable-glusterfs --enable-libusb --enable-usb-redir \
- --disable-opengl --disable-xen --enable-spice \
- --enable-debug --disable-capstone --disable-kvm \
- --enable-profiler
+ ./configure --target-list="loongarch64-softmmu"
make -j8
(2) Set cross tools:
@@ -53,9 +48,7 @@ can be accessed by following steps.
.. code-block:: bash
wget https://github.com/loongson/build-tools/releases/download/2022.09.06/loongarch64-clfs-6.3-cross-tools-gcc-glibc.tar.xz
-
tar -vxf loongarch64-clfs-6.3-cross-tools-gcc-glibc.tar.xz -C /opt
-
export PATH=/opt/cross-tools/bin:$PATH
export LD_LIBRARY_PATH=/opt/cross-tools/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/opt/cross-tools/loongarch64-unknown-linux-gnu/lib/:$LD_LIBRARY_PATH
@@ -74,13 +67,9 @@ Note: To build the release version of the bios, set --buildtarget=RELEASE,
.. code-block:: bash
git clone https://github.com/loongson/linux.git
-
cd linux
-
git checkout loongarch-next
-
make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- loongson3_defconfig
-
make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- -j32
Note: The branch of linux source code is loongarch-next.
diff --git a/docs/system/target-loongarch.rst b/docs/system/target-loongarch.rst
new file mode 100644
index 0000000..316c604
--- /dev/null
+++ b/docs/system/target-loongarch.rst
@@ -0,0 +1,19 @@
+.. _LoongArch-System-emulator:
+
+LoongArch System emulator
+-------------------------
+
+QEMU can emulate loongArch 64 bit systems via the
+``qemu-system-loongarch64`` binary. Only one machine type ``virt`` is
+supported.
+
+When using KVM as accelerator, QEMU can emulate la464 cpu model. And when
+using the default cpu model with TCG as accelerator, QEMU will emulate a
+subset of la464 cpu features that should be enough to run distributions
+built for the la464.
+
+Board-specific documentation
+============================
+
+.. toctree::
+ loongarch/virt
diff --git a/docs/system/targets.rst b/docs/system/targets.rst
index 224fada..38e2418 100644
--- a/docs/system/targets.rst
+++ b/docs/system/targets.rst
@@ -18,6 +18,7 @@ Contents:
target-arm
target-avr
+ target-loongarch
target-m68k
target-mips
target-ppc
diff --git a/host/include/loongarch64/host/atomic128-ldst.h.inc b/host/include/loongarch64/host/atomic128-ldst.h.inc
index 9a4a8f8..754d214 100644
--- a/host/include/loongarch64/host/atomic128-ldst.h.inc
+++ b/host/include/loongarch64/host/atomic128-ldst.h.inc
@@ -28,7 +28,7 @@ static inline Int128 atomic16_read_ro(const Int128 *ptr)
asm("vld $vr0, %2, 0\n\t"
"vpickve2gr.d %0, $vr0, 0\n\t"
"vpickve2gr.d %1, $vr0, 1"
- : "=r"(l), "=r"(h) : "r"(ptr), "m"(*ptr) : "f0");
+ : "=r"(l), "=r"(h) : "r"(ptr), "m"(*ptr) : "$f0");
return int128_make128(l, h);
}
@@ -46,7 +46,7 @@ static inline void atomic16_set(Int128 *ptr, Int128 val)
asm("vinsgr2vr.d $vr0, %1, 0\n\t"
"vinsgr2vr.d $vr0, %2, 1\n\t"
"vst $vr0, %3, 0"
- : "=m"(*ptr) : "r"(l), "r"(h), "r"(ptr) : "f0");
+ : "=m"(*ptr) : "r"(l), "r"(h), "r"(ptr) : "$f0");
}
#endif /* LOONGARCH_ATOMIC128_LDST_H */
diff --git a/host/include/loongarch64/host/bufferiszero.c.inc b/host/include/loongarch64/host/bufferiszero.c.inc
index 69891ea..bb2598f 100644
--- a/host/include/loongarch64/host/bufferiszero.c.inc
+++ b/host/include/loongarch64/host/bufferiszero.c.inc
@@ -61,7 +61,8 @@ static bool buffer_is_zero_lsx(const void *buf, size_t len)
"2:"
: "=&r"(ret), "+r"(p)
: "r"(buf), "r"(e), "r"(l)
- : "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "fcc0");
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8",
+ "$fcc0");
return ret;
}
@@ -119,7 +120,8 @@ static bool buffer_is_zero_lasx(const void *buf, size_t len)
"3:"
: "=&r"(ret), "+r"(p)
: "r"(buf), "r"(e), "r"(l)
- : "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "fcc0");
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8",
+ "$fcc0");
return ret;
}
diff --git a/host/include/loongarch64/host/load-extract-al16-al8.h.inc b/host/include/loongarch64/host/load-extract-al16-al8.h.inc
index d1fb59d..9528521 100644
--- a/host/include/loongarch64/host/load-extract-al16-al8.h.inc
+++ b/host/include/loongarch64/host/load-extract-al16-al8.h.inc
@@ -31,7 +31,7 @@ static inline uint64_t load_atom_extract_al16_or_al8(void *pv, int s)
asm("vld $vr0, %2, 0\n\t"
"vpickve2gr.d %0, $vr0, 0\n\t"
"vpickve2gr.d %1, $vr0, 1"
- : "=r"(l), "=r"(h) : "r"(ptr_align), "m"(*ptr_align) : "f0");
+ : "=r"(l), "=r"(h) : "r"(ptr_align), "m"(*ptr_align) : "$f0");
return (l >> shr) | (h << (-shr & 63));
}
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 15200a2..a55b44d 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -21,8 +21,7 @@ config ARM_VIRT
select PCI_EXPRESS
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL031 # RTC
select PL061 # GPIO
select GPIO_PWR
@@ -75,8 +74,7 @@ config HIGHBANK
select AHCI_SYSBUS
select ARM_TIMER # sp804
select ARM_V7M
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL022 # SPI
select PL031 # RTC
select PL061 # GPIO
@@ -89,8 +87,7 @@ config INTEGRATOR
depends on TCG && ARM
select ARM_TIMER
select INTEGRATOR_DEBUG
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL031 # RTC
select PL041 # audio
select PL050 # keyboard/mouse
@@ -108,8 +105,7 @@ config MUSCA
default y
depends on TCG && ARM
select ARMSSE
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL031
select SPLIT_IRQ
select UNIMP
@@ -173,8 +169,7 @@ config REALVIEW
select WM8750 # audio codec
select LSI_SCSI_PCI
select PCI
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL031 # RTC
select PL041 # audio codec
select PL050 # keyboard/mouse
@@ -199,8 +194,7 @@ config SBSA_REF
select PCI_EXPRESS
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL031 # RTC
select PL061 # GPIO
select USB_XHCI_SYSBUS
@@ -224,8 +218,7 @@ config STELLARIS
select ARM_V7M
select CMSDK_APB_WATCHDOG
select I2C
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL022 # SPI
select PL061 # GPIO
select SSD0303 # OLED display
@@ -285,8 +278,7 @@ config VEXPRESS
select ARM_TIMER # sp804
select LAN9118
select PFLASH_CFI01
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select PL041 # audio codec
select PL181 # display
select REALVIEW
@@ -371,8 +363,7 @@ config RASPI
default y
depends on TCG && ARM
select FRAMEBUFFER
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select SDHCI
select USB_DWC2
select BCM2835_SPI
@@ -448,8 +439,7 @@ config XLNX_VERSAL
select ARM_GIC
select CPU_CLUSTER
select DEVICE_TREE
- select PL011 if !HAVE_RUST # UART
- select X_PL011_RUST if HAVE_RUST # UART
+ select PL011 # UART
select CADENCE
select VIRTIO_MMIO
select UNIMP
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 3f70256..9d517f3 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -11,6 +11,12 @@ config PARALLEL
config PL011
bool
+ # The PL011 has both a Rust and a C implementation
+ select PL011_C if !HAVE_RUST
+ select X_PL011_RUST if HAVE_RUST
+
+config PL011_C
+ bool
config SERIAL
bool
diff --git a/hw/char/meson.build b/hw/char/meson.build
index 86ee808..4e439da 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -9,7 +9,7 @@ system_ss.add(when: 'CONFIG_ISA_BUS', if_true: files('parallel-isa.c'))
system_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugcon.c'))
system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_uart.c'))
system_ss.add(when: 'CONFIG_PARALLEL', if_true: files('parallel.c'))
-system_ss.add(when: 'CONFIG_PL011', if_true: files('pl011.c'))
+system_ss.add(when: 'CONFIG_PL011_C', if_true: files('pl011.c'))
system_ss.add(when: 'CONFIG_SCLPCONSOLE', if_true: files('sclpconsole.c', 'sclpconsole-lm.c'))
system_ss.add(when: 'CONFIG_SERIAL', if_true: files('serial.c'))
system_ss.add(when: 'CONFIG_SERIAL_ISA', if_true: files('serial-isa.c'))
diff --git a/hw/core/loader.c b/hw/core/loader.c
index ce6ff1b..2e35f0a 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -226,7 +226,7 @@ static void bswap_ahdr(struct exec *e)
ssize_t load_aout(const char *filename, hwaddr addr, int max_sz,
- int bswap_needed, hwaddr target_page_size)
+ bool big_endian, hwaddr target_page_size)
{
int fd;
ssize_t size, ret;
@@ -241,7 +241,7 @@ ssize_t load_aout(const char *filename, hwaddr addr, int max_sz,
if (size < 0)
goto fail;
- if (bswap_needed) {
+ if (big_endian != HOST_BIG_ENDIAN) {
bswap_ahdr(&e);
}
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index c04df3b..147b3ff 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -442,6 +442,43 @@ const PropertyInfo qdev_prop_uint64_checkmask = {
.set = set_uint64_checkmask,
};
+/* --- pointer-size integer --- */
+
+static void get_usize(Object *obj, Visitor *v, const char *name, void *opaque,
+ Error **errp)
+{
+ const Property *prop = opaque;
+
+#if HOST_LONG_BITS == 32
+ uint32_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint32(v, name, ptr, errp);
+#else
+ uint64_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint64(v, name, ptr, errp);
+#endif
+}
+
+static void set_usize(Object *obj, Visitor *v, const char *name, void *opaque,
+ Error **errp)
+{
+ const Property *prop = opaque;
+
+#if HOST_LONG_BITS == 32
+ uint32_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint32(v, name, ptr, errp);
+#else
+ uint64_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint64(v, name, ptr, errp);
+#endif
+}
+
+const PropertyInfo qdev_prop_usize = {
+ .type = "usize",
+ .get = get_usize,
+ .set = set_usize,
+ .set_default_value = qdev_propinfo_set_default_value_uint,
+};
+
/* --- string --- */
static void release_string(Object *obj, const char *name, void *opaque)
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
index a7f1b60..5c0bcd5 100644
--- a/hw/i386/fw_cfg.c
+++ b/hw/i386/fw_cfg.c
@@ -26,7 +26,7 @@
#include CONFIG_DEVICES
#include "target/i386/cpu.h"
-#if !defined(CONFIG_HPET) && !defined(CONFIG_X_HPET_RUST)
+#if !defined(CONFIG_HPET)
struct hpet_fw_config hpet_fw_cfg = {.count = UINT8_MAX};
#endif
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 63a96cd..01d0581 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1704,7 +1704,7 @@ static void pc_machine_initfn(Object *obj)
pcms->sata_enabled = true;
pcms->i8042_enabled = true;
pcms->max_fw_size = 8 * MiB;
-#if defined(CONFIG_HPET) || defined(CONFIG_X_HPET_RUST)
+#if defined(CONFIG_HPET)
pcms->hpet_enabled = true;
#endif
pcms->fd_bootchk = true;
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index c77df2c..3eb28c2 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -1662,12 +1662,20 @@ uint32_t xive_get_vpgroup_size(uint32_t nvp_index)
* (starting with the least significant bits) in the NVP index
* gives the size of the group.
*/
- return 1 << (ctz32(~nvp_index) + 1);
+ int first_zero = cto32(nvp_index);
+ if (first_zero >= 31) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid group index 0x%08x",
+ nvp_index);
+ return 0;
+ }
+
+ return 1U << (first_zero + 1);
}
static uint8_t xive_get_group_level(bool crowd, bool ignore,
uint32_t nvp_blk, uint32_t nvp_index)
{
+ int first_zero;
uint8_t level;
if (!ignore) {
@@ -1675,18 +1683,31 @@ static uint8_t xive_get_group_level(bool crowd, bool ignore,
return 0;
}
- level = (ctz32(~nvp_index) + 1) & 0b1111;
+ first_zero = cto32(nvp_index);
+ if (first_zero >= 31) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid group index 0x%08x",
+ nvp_index);
+ return 0;
+ }
+
+ level = (first_zero + 1) & 0b1111;
if (crowd) {
uint32_t blk;
/* crowd level is bit position of first 0 from the right in nvp_blk */
- blk = ctz32(~nvp_blk) + 1;
+ first_zero = cto32(nvp_blk);
+ if (first_zero >= 31) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid crowd block 0x%08x",
+ nvp_blk);
+ return 0;
+ }
+ blk = first_zero + 1;
/*
* Supported crowd sizes are 2^1, 2^2, and 2^4. 2^3 is not supported.
* HW will encode level 4 as the value 3. See xive2_pgofnext().
*/
- switch (level) {
+ switch (blk) {
case 1:
case 2:
break;
diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c
index f8ef615..7d584df 100644
--- a/hw/intc/xive2.c
+++ b/hw/intc/xive2.c
@@ -1153,13 +1153,15 @@ static bool xive2_vp_match_mask(uint32_t cam1, uint32_t cam2,
static uint8_t xive2_get_vp_block_mask(uint32_t nvt_blk, bool crowd)
{
- uint8_t size, block_mask = 0b1111;
+ uint8_t block_mask = 0b1111;
/* 3 supported crowd sizes: 2, 4, 16 */
if (crowd) {
- size = xive_get_vpgroup_size(nvt_blk);
- if (size == 8) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid crowd size of 8n");
+ uint32_t size = xive_get_vpgroup_size(nvt_blk);
+
+ if (size != 2 && size != 4 && size != 16) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid crowd size of %d",
+ size);
return block_mask;
}
block_mask &= ~(size - 1);
@@ -1172,7 +1174,14 @@ static uint32_t xive2_get_vp_index_mask(uint32_t nvt_index, bool cam_ignore)
uint32_t index_mask = 0xFFFFFF; /* 24 bits */
if (cam_ignore) {
- index_mask &= ~(xive_get_vpgroup_size(nvt_index) - 1);
+ uint32_t size = xive_get_vpgroup_size(nvt_index);
+
+ if (size < 2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid group size of %d",
+ size);
+ return index_mask;
+ }
+ index_mask &= ~(size - 1);
}
return index_mask;
}
@@ -1335,7 +1344,7 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
return;
}
- if (xive2_end_is_crowd(&end) & !xive2_end_is_ignore(&end)) {
+ if (xive2_end_is_crowd(&end) && !xive2_end_is_ignore(&end)) {
qemu_log_mask(LOG_GUEST_ERROR,
"XIVE: invalid END, 'crowd' bit requires 'ignore' bit\n");
return;
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index a5840ff..e258642 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -38,6 +38,7 @@
#include "hw/mem/nvdimm.h"
#include "hw/platform-bus.h"
#include "hw/display/ramfb.h"
+#include "hw/uefi/var-service-api.h"
#include "hw/mem/pc-dimm.h"
#include "system/tpm.h"
#include "system/block-backend.h"
@@ -327,7 +328,6 @@ static void virt_cpu_irq_init(LoongArchVirtMachineState *lvms)
MachineClass *mc = MACHINE_GET_CLASS(ms);
const CPUArchIdList *possible_cpus;
CPUState *cs;
- Error *err = NULL;
/* cpu nodes */
possible_cpus = mc->possible_cpu_arch_ids(ms);
@@ -337,8 +337,10 @@ static void virt_cpu_irq_init(LoongArchVirtMachineState *lvms)
continue;
}
- hotplug_handler_plug(HOTPLUG_HANDLER(lvms->ipi), DEVICE(cs), &err);
- hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), DEVICE(cs), &err);
+ hotplug_handler_plug(HOTPLUG_HANDLER(lvms->ipi), DEVICE(cs),
+ &error_abort);
+ hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), DEVICE(cs),
+ &error_abort);
}
}
@@ -859,30 +861,29 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
LoongArchCPU *cpu = LOONGARCH_CPU(dev);
CPUState *cs = CPU(dev);
CPUArchId *cpu_slot;
- Error *err = NULL;
LoongArchCPUTopo topo;
int arch_id;
if (lvms->acpi_ged) {
if ((cpu->thread_id < 0) || (cpu->thread_id >= ms->smp.threads)) {
- error_setg(&err,
+ error_setg(errp,
"Invalid thread-id %u specified, must be in range 1:%u",
cpu->thread_id, ms->smp.threads - 1);
- goto out;
+ return;
}
if ((cpu->core_id < 0) || (cpu->core_id >= ms->smp.cores)) {
- error_setg(&err,
+ error_setg(errp,
"Invalid core-id %u specified, must be in range 1:%u",
cpu->core_id, ms->smp.cores - 1);
- goto out;
+ return;
}
if ((cpu->socket_id < 0) || (cpu->socket_id >= ms->smp.sockets)) {
- error_setg(&err,
+ error_setg(errp,
"Invalid socket-id %u specified, must be in range 1:%u",
cpu->socket_id, ms->smp.sockets - 1);
- goto out;
+ return;
}
topo.socket_id = cpu->socket_id;
@@ -891,11 +892,11 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
arch_id = virt_get_arch_id_from_topo(ms, &topo);
cpu_slot = virt_find_cpu_slot(ms, arch_id);
if (CPU(cpu_slot->cpu)) {
- error_setg(&err,
+ error_setg(errp,
"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;
+ return;
}
} else {
/* For cold-add cpu, find empty cpu slot */
@@ -911,33 +912,24 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
cpu->env.address_space_iocsr = &lvms->as_iocsr;
cpu->phy_id = cpu_slot->arch_id;
cs->cpu_index = cpu_slot - ms->possible_cpus->cpus;
- numa_cpu_pre_plug(cpu_slot, dev, &err);
-out:
- if (err) {
- error_propagate(errp, err);
- }
+ numa_cpu_pre_plug(cpu_slot, dev, errp);
}
static void virt_cpu_unplug_request(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
- Error *err = NULL;
LoongArchCPU *cpu = LOONGARCH_CPU(dev);
CPUState *cs = CPU(dev);
if (cs->cpu_index == 0) {
- error_setg(&err, "hot-unplug of boot cpu(id%d=%d:%d:%d) not supported",
+ error_setg(errp, "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, err);
return;
}
- hotplug_handler_unplug_request(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &err);
- if (err) {
- error_propagate(errp, err);
- }
+ hotplug_handler_unplug_request(HOTPLUG_HANDLER(lvms->acpi_ged), dev, errp);
}
static void virt_cpu_unplug(HotplugHandler *hotplug_dev,
@@ -1207,6 +1199,7 @@ static void virt_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "v-eiointc",
"Enable Virt Extend I/O Interrupt Controller.");
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
#ifdef CONFIG_TPM
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
#endif
diff --git a/hw/ppc/amigaone.c b/hw/ppc/amigaone.c
index 4835121..e9407a5 100644
--- a/hw/ppc/amigaone.c
+++ b/hw/ppc/amigaone.c
@@ -63,7 +63,7 @@ static const char dummy_fw[] = {
#define NVRAM_ADDR 0xfd0e0000
#define NVRAM_SIZE (4 * KiB)
-static char default_env[] =
+static const char default_env[] =
"baudrate=115200\0"
"stdout=vga\0"
"stdin=ps2kbd\0"
@@ -108,8 +108,8 @@ static void nvram_write(void *opaque, hwaddr addr, uint64_t val,
uint8_t *p = memory_region_get_ram_ptr(&s->mr);
p[addr] = val;
- if (s->blk) {
- blk_pwrite(s->blk, addr, 1, &val, 0);
+ if (s->blk && blk_pwrite(s->blk, addr, 1, &val, 0) < 0) {
+ error_report("%s: could not write %s", __func__, blk_name(s->blk));
}
}
@@ -151,15 +151,17 @@ static void nvram_realize(DeviceState *dev, Error **errp)
*c = cpu_to_be32(CRC32_DEFAULT_ENV);
/* Also copies terminating \0 as env is terminated by \0\0 */
memcpy(p + 4, default_env, sizeof(default_env));
- if (s->blk) {
- blk_pwrite(s->blk, 0, sizeof(crc) + sizeof(default_env), p, 0);
+ if (s->blk &&
+ blk_pwrite(s->blk, 0, sizeof(crc) + sizeof(default_env), p, 0) < 0
+ ) {
+ error_report("%s: could not write %s", __func__, blk_name(s->blk));
}
return;
}
if (*c == 0) {
*c = cpu_to_be32(crc32(0, p + 4, NVRAM_SIZE - 4));
- if (s->blk) {
- blk_pwrite(s->blk, 0, 4, p, 0);
+ if (s->blk && blk_pwrite(s->blk, 0, 4, p, 0) < 0) {
+ error_report("%s: could not write %s", __func__, blk_name(s->blk));
}
}
if (be32_to_cpu(*c) != crc) {
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index cb3dc3a..2d5309d 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -197,11 +197,6 @@ static void ppc_core99_init(MachineState *machine)
}
if (machine->kernel_filename) {
- int bswap_needed = 0;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#endif
kernel_base = KERNEL_LOAD_ADDR;
kernel_size = load_elf(machine->kernel_filename, NULL,
translate_kernel_address, NULL, NULL, NULL,
@@ -209,7 +204,7 @@ static void ppc_core99_init(MachineState *machine)
if (kernel_size < 0) {
kernel_size = load_aout(machine->kernel_filename, kernel_base,
machine->ram_size - kernel_base,
- bswap_needed, TARGET_PAGE_SIZE);
+ true, TARGET_PAGE_SIZE);
}
if (kernel_size < 0) {
kernel_size = load_image_targphys(machine->kernel_filename,
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 0dbcea0..b581469 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -153,11 +153,6 @@ static void ppc_heathrow_init(MachineState *machine)
}
if (machine->kernel_filename) {
- int bswap_needed = 0;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#endif
kernel_base = KERNEL_LOAD_ADDR;
kernel_size = load_elf(machine->kernel_filename, NULL,
translate_kernel_address, NULL, NULL, NULL,
@@ -165,7 +160,7 @@ static void ppc_heathrow_init(MachineState *machine)
if (kernel_size < 0) {
kernel_size = load_aout(machine->kernel_filename, kernel_base,
machine->ram_size - kernel_base,
- bswap_needed, TARGET_PAGE_SIZE);
+ true, TARGET_PAGE_SIZE);
}
if (kernel_size < 0) {
kernel_size = load_image_targphys(machine->kernel_filename,
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 5936537..63f2232 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1191,7 +1191,7 @@ static void pnv_init(MachineState *machine)
* Since we can not reach the remote BMC machine with LPC memops,
* map it always for now.
*/
- memory_region_add_subregion(pnv->chips[0]->fw_mr, PNOR_SPI_OFFSET,
+ memory_region_add_subregion(pnv->chips[0]->fw_mr, pnv->pnor->lpc_address,
&pnv->pnor->mmio);
/*
diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c
index 811ba3d..fb70a8c 100644
--- a/hw/ppc/pnv_bmc.c
+++ b/hw/ppc/pnv_bmc.c
@@ -174,8 +174,8 @@ static void hiomap_cmd(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len,
{
PnvPnor *pnor = PNV_PNOR(object_property_get_link(OBJECT(ibs), "pnor",
&error_abort));
+ uint32_t pnor_addr = pnor->lpc_address;
uint32_t pnor_size = pnor->size;
- uint32_t pnor_addr = PNOR_SPI_OFFSET;
bool readonly = false;
rsp_buffer_push(rsp, cmd[2]);
@@ -251,8 +251,8 @@ static const IPMINetfn hiomap_netfn = {
void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor)
{
+ uint32_t pnor_addr = pnor->lpc_address;
uint32_t pnor_size = pnor->size;
- uint32_t pnor_addr = PNOR_SPI_OFFSET;
if (!pnv_bmc_is_simulator(bmc)) {
return;
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 99d9644..a33977d 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -248,21 +248,25 @@ static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
if (val & PPC_BIT(7 + 8 * i)) { /* stop */
val &= ~PPC_BIT(7 + 8 * i);
- cpu_pause(cs);
env->quiesced = true;
+ ppc_maybe_interrupt(env);
+ cpu_pause(cs);
}
if (val & PPC_BIT(6 + 8 * i)) { /* start */
val &= ~PPC_BIT(6 + 8 * i);
env->quiesced = false;
+ ppc_maybe_interrupt(env);
cpu_resume(cs);
}
if (val & PPC_BIT(4 + 8 * i)) { /* sreset */
val &= ~PPC_BIT(4 + 8 * i);
env->quiesced = false;
+ ppc_maybe_interrupt(env);
pnv_cpu_do_nmi_resume(cs);
}
if (val & PPC_BIT(3 + 8 * i)) { /* clear maint */
env->quiesced = false;
+ ppc_maybe_interrupt(env);
/*
* Hardware has very particular cases for where clear maint
* must be used and where start must be used to resume a
diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
index bda6b23..177c5e5 100644
--- a/hw/ppc/pnv_occ.c
+++ b/hw/ppc/pnv_occ.c
@@ -364,7 +364,12 @@ static void pnv_occ_register_types(void)
type_init(pnv_occ_register_types);
-/* From skiboot/hw/occ.c with tab to space conversion */
+/*
+ * From skiboot/hw/occ.c with following changes:
+ * - tab to space conversion
+ * - Type conversions u8->uint8_t s8->int8_t __be16->uint16_t etc
+ * - __packed -> QEMU_PACKED
+ */
/* OCC Communication Area for PStates */
#define OPAL_DYNAMIC_DATA_OFFSET 0x0B80
@@ -384,20 +389,6 @@ type_init(pnv_occ_register_types);
#define FREQ_MAX_IN_DOMAIN 0
#define FREQ_MOST_RECENTLY_SET 1
-#define u8 uint8_t
-#define s8 int8_t
-#define u16 uint16_t
-#define s16 int16_t
-#define u32 uint32_t
-#define s32 int32_t
-#define u64 uint64_t
-#define s64 int64_t
-#define __be16 uint16_t
-#define __be32 uint32_t
-#ifndef __packed
-#define __packed QEMU_PACKED
-#endif /* !__packed */
-
/**
* OCC-OPAL Shared Memory Region
*
@@ -434,69 +425,69 @@ type_init(pnv_occ_register_types);
* @spare/reserved/pad: Unused data
*/
struct occ_pstate_table {
- u8 valid;
- u8 version;
- union __packed {
- struct __packed { /* Version 0x01 and 0x02 */
- u8 throttle;
- s8 pstate_min;
- s8 pstate_nom;
- s8 pstate_turbo;
- s8 pstate_ultra_turbo;
- u8 spare;
- u64 reserved;
- struct __packed {
- s8 id;
- u8 flags;
- u8 vdd;
- u8 vcs;
- __be32 freq_khz;
+ uint8_t valid;
+ uint8_t version;
+ union QEMU_PACKED {
+ struct QEMU_PACKED { /* Version 0x01 and 0x02 */
+ uint8_t throttle;
+ int8_t pstate_min;
+ int8_t pstate_nom;
+ int8_t pstate_turbo;
+ int8_t pstate_ultra_turbo;
+ uint8_t spare;
+ uint64_t reserved;
+ struct QEMU_PACKED {
+ int8_t id;
+ uint8_t flags;
+ uint8_t vdd;
+ uint8_t vcs;
+ uint32_t freq_khz;
} pstates[MAX_PSTATES];
- s8 core_max[MAX_P8_CORES];
- u8 pad[100];
+ int8_t core_max[MAX_P8_CORES];
+ uint8_t pad[100];
} v2;
- struct __packed { /* Version 0x90 */
- u8 occ_role;
- u8 pstate_min;
- u8 pstate_nom;
- u8 pstate_turbo;
- u8 pstate_ultra_turbo;
- u8 spare;
- u64 reserved1;
- u64 reserved2;
- struct __packed {
- u8 id;
- u8 flags;
- u16 reserved;
- __be32 freq_khz;
+ struct QEMU_PACKED { /* Version 0x90 */
+ uint8_t occ_role;
+ uint8_t pstate_min;
+ uint8_t pstate_nom;
+ uint8_t pstate_turbo;
+ uint8_t pstate_ultra_turbo;
+ uint8_t spare;
+ uint64_t reserved1;
+ uint64_t reserved2;
+ struct QEMU_PACKED {
+ uint8_t id;
+ uint8_t flags;
+ uint16_t reserved;
+ uint32_t freq_khz;
} pstates[MAX_PSTATES];
- u8 core_max[MAX_P9_CORES];
- u8 pad[56];
+ uint8_t core_max[MAX_P9_CORES];
+ uint8_t pad[56];
} v9;
- struct __packed { /* Version 0xA0 */
- u8 occ_role;
- u8 pstate_min;
- u8 pstate_fixed_freq;
- u8 pstate_base;
- u8 pstate_ultra_turbo;
- u8 pstate_fmax;
- u8 minor;
- u8 pstate_bottom_throttle;
- u8 spare;
- u8 spare1;
- u32 reserved_32;
- u64 reserved_64;
- struct __packed {
- u8 id;
- u8 valid;
- u16 reserved;
- __be32 freq_khz;
+ struct QEMU_PACKED { /* Version 0xA0 */
+ uint8_t occ_role;
+ uint8_t pstate_min;
+ uint8_t pstate_fixed_freq;
+ uint8_t pstate_base;
+ uint8_t pstate_ultra_turbo;
+ uint8_t pstate_fmax;
+ uint8_t minor;
+ uint8_t pstate_bottom_throttle;
+ uint8_t spare;
+ uint8_t spare1;
+ uint32_t reserved_32;
+ uint64_t reserved_64;
+ struct QEMU_PACKED {
+ uint8_t id;
+ uint8_t valid;
+ uint16_t reserved;
+ uint32_t freq_khz;
} pstates[MAX_PSTATES];
- u8 core_max[MAX_P10_CORES];
- u8 pad[48];
+ uint8_t core_max[MAX_P10_CORES];
+ uint8_t pad[48];
} v10;
};
-} __packed;
+} QEMU_PACKED;
/**
* OPAL-OCC Command Response Interface
@@ -531,13 +522,13 @@ struct occ_pstate_table {
* @spare: Unused byte
*/
struct opal_command_buffer {
- u8 flag;
- u8 request_id;
- u8 cmd;
- u8 spare;
- __be16 data_size;
- u8 data[MAX_OPAL_CMD_DATA_LENGTH];
-} __packed;
+ uint8_t flag;
+ uint8_t request_id;
+ uint8_t cmd;
+ uint8_t spare;
+ uint16_t data_size;
+ uint8_t data[MAX_OPAL_CMD_DATA_LENGTH];
+} QEMU_PACKED;
/**
* OPAL-OCC Response Buffer
@@ -571,13 +562,13 @@ struct opal_command_buffer {
* @data: Response specific data
*/
struct occ_response_buffer {
- u8 flag;
- u8 request_id;
- u8 cmd;
- u8 status;
- __be16 data_size;
- u8 data[MAX_OCC_RSP_DATA_LENGTH];
-} __packed;
+ uint8_t flag;
+ uint8_t request_id;
+ uint8_t cmd;
+ uint8_t status;
+ uint16_t data_size;
+ uint8_t data[MAX_OCC_RSP_DATA_LENGTH];
+} QEMU_PACKED;
/**
* OCC-OPAL Shared Memory Interface Dynamic Data Vx90
@@ -608,31 +599,31 @@ struct occ_response_buffer {
* @rsp: OCC Response Buffer
*/
struct occ_dynamic_data {
- u8 occ_state;
- u8 major_version;
- u8 minor_version;
- u8 gpus_present;
- union __packed {
- struct __packed { /* Version 0x90 */
- u8 spare1;
+ uint8_t occ_state;
+ uint8_t major_version;
+ uint8_t minor_version;
+ uint8_t gpus_present;
+ union QEMU_PACKED {
+ struct QEMU_PACKED { /* Version 0x90 */
+ uint8_t spare1;
} v9;
- struct __packed { /* Version 0xA0 */
- u8 wof_enabled;
+ struct QEMU_PACKED { /* Version 0xA0 */
+ uint8_t wof_enabled;
} v10;
};
- u8 cpu_throttle;
- u8 mem_throttle;
- u8 quick_pwr_drop;
- u8 pwr_shifting_ratio;
- u8 pwr_cap_type;
- __be16 hard_min_pwr_cap;
- __be16 max_pwr_cap;
- __be16 cur_pwr_cap;
- __be16 soft_min_pwr_cap;
- u8 pad[110];
+ uint8_t cpu_throttle;
+ uint8_t mem_throttle;
+ uint8_t quick_pwr_drop;
+ uint8_t pwr_shifting_ratio;
+ uint8_t pwr_cap_type;
+ uint16_t hard_min_pwr_cap;
+ uint16_t max_pwr_cap;
+ uint16_t cur_pwr_cap;
+ uint16_t soft_min_pwr_cap;
+ uint8_t pad[110];
struct opal_command_buffer cmd;
struct occ_response_buffer rsp;
-} __packed;
+} QEMU_PACKED;
enum occ_response_status {
OCC_RSP_SUCCESS = 0x00,
diff --git a/hw/ppc/pnv_pnor.c b/hw/ppc/pnv_pnor.c
index 863e2e7..9db44ca 100644
--- a/hw/ppc/pnv_pnor.c
+++ b/hw/ppc/pnv_pnor.c
@@ -108,6 +108,8 @@ static void pnv_pnor_realize(DeviceState *dev, Error **errp)
memset(s->storage, 0xFF, s->size);
}
+ s->lpc_address = PNOR_SPI_OFFSET;
+
memory_region_init_io(&s->mmio, OBJECT(s), &pnv_pnor_ops, s,
TYPE_PNV_PNOR, s->size);
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index a415e51..b0a0f8c 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -296,6 +296,7 @@ static void spapr_dt_pa_features(SpaprMachineState *spapr,
pa_features[40 + 2] &= ~0x80; /* Radix MMU */
}
if (spapr_get_cap(spapr, SPAPR_CAP_DAWR1)) {
+ g_assert(pa_size > 66);
pa_features[66] |= 0x80;
}
@@ -4815,6 +4816,7 @@ static void spapr_machine_8_2_class_options(MachineClass *mc)
{
spapr_machine_9_0_class_options(mc);
compat_props_add(mc->compat_props, hw_compat_8_2, hw_compat_8_2_len);
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.2");
}
DEFINE_SPAPR_MACHINE(8, 2);
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 0671d9e..faf9170 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -37,6 +37,9 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
cpu_reset(cs);
+ env->quiesced = true; /* set "RTAS stopped" state. */
+ ppc_maybe_interrupt(env);
+
/*
* "PowerPC Processor binding to IEEE 1275" defines the initial MSR state
* as 32bit (MSR_SF=0) with MSR_ME=1 and MSR_FP=1 in "8.2.1. Initial
@@ -98,6 +101,9 @@ void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip,
CPU(cpu)->halted = 0;
/* Enable Power-saving mode Exit Cause exceptions */
ppc_store_lpcr(cpu, env->spr[SPR_LPCR] | pcc->lpcr_pm);
+
+ env->quiesced = false; /* clear "RTAS stopped" state. */
+ ppc_maybe_interrupt(env);
}
/*
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 503d441..78309db 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -110,7 +110,8 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
id = rtas_ld(args, 0);
cpu = spapr_find_cpu(id);
if (cpu != NULL) {
- if (CPU(cpu)->halted) {
+ CPUPPCState *env = &cpu->env;
+ if (env->quiesced) {
rtas_st(rets, 1, 0);
} else {
rtas_st(rets, 1, 2);
@@ -215,6 +216,8 @@ static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr,
* For the same reason, set PSSCR_EC.
*/
env->spr[SPR_PSSCR] |= PSSCR_EC;
+ env->quiesced = true; /* set "RTAS stopped" state. */
+ ppc_maybe_interrupt(env);
cs->halted = 1;
ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
kvmppc_set_reg_ppc_online(cpu, 0);
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index dae46f4..e517002 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -57,6 +57,7 @@
#include "hw/acpi/aml-build.h"
#include "qapi/qapi-visit-common.h"
#include "hw/virtio/virtio-iommu.h"
+#include "hw/uefi/var-service-api.h"
/* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */
static bool virt_use_kvm_aia_aplic_imsic(RISCVVirtAIAType aia_type)
@@ -1935,6 +1936,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
hc->plug = virt_machine_device_plug_cb;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
#ifdef CONFIG_TPM
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
#endif
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index a48d362..5aaafb4 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -233,20 +233,13 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename,
kernel_size = 0;
if (linux_boot) {
- int bswap_needed;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#else
- bswap_needed = 0;
-#endif
kernel_size = load_elf(kernel_filename, NULL,
translate_kernel_address, NULL,
NULL, NULL, NULL, NULL,
ELFDATA2MSB, EM_SPARC, 0, 0);
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
- RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+ RAM_size - KERNEL_LOAD_ADDR, true,
TARGET_PAGE_SIZE);
if (kernel_size < 0)
kernel_size = load_image_targphys(kernel_filename,
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 8ab5cf0..d3cb727 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -168,13 +168,6 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
kernel_size = 0;
if (linux_boot) {
- int bswap_needed;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#else
- bswap_needed = 0;
-#endif
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, kernel_entry,
kernel_addr, &kernel_top, NULL,
ELFDATA2MSB, EM_SPARCV9, 0, 0);
@@ -182,7 +175,7 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
*kernel_addr = KERNEL_LOAD_ADDR;
*kernel_entry = KERNEL_LOAD_ADDR;
kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
- RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+ RAM_size - KERNEL_LOAD_ADDR, true,
TARGET_PAGE_SIZE);
}
if (kernel_size < 0) {
diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig
index 9ac0084..b3d823c 100644
--- a/hw/timer/Kconfig
+++ b/hw/timer/Kconfig
@@ -11,7 +11,13 @@ config A9_GTIMER
config HPET
bool
- default y if PC && !HAVE_RUST
+ default y if PC
+ # The HPET has both a Rust and a C implementation
+ select HPET_C if !HAVE_RUST
+ select X_HPET_RUST if HAVE_RUST
+
+config HPET_C
+ bool
config I8254
bool
diff --git a/hw/timer/meson.build b/hw/timer/meson.build
index f5f9eed..178321c 100644
--- a/hw/timer/meson.build
+++ b/hw/timer/meson.build
@@ -13,7 +13,7 @@ system_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic-timer.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_mct.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pwm.c'))
system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_gptimer.c'))
-system_ss.add(when: 'CONFIG_HPET', if_true: files('hpet.c'))
+system_ss.add(when: 'CONFIG_HPET_C', if_true: files('hpet.c'))
system_ss.add(when: 'CONFIG_I8254', if_true: files('i8254_common.c', 'i8254.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_epit.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpt.c'))
diff --git a/hw/uefi/Kconfig b/hw/uefi/Kconfig
index ca6c2bc..046d553 100644
--- a/hw/uefi/Kconfig
+++ b/hw/uefi/Kconfig
@@ -1,3 +1,3 @@
config UEFI_VARS
bool
- default y if X86_64 || AARCH64
+ default y if X86_64 || AARCH64 || RISCV64 || LOONGARCH64
diff --git a/hw/uefi/var-service-core.c b/hw/uefi/var-service-core.c
index 8ed8378..4836a0c 100644
--- a/hw/uefi/var-service-core.c
+++ b/hw/uefi/var-service-core.c
@@ -29,6 +29,7 @@ static int uefi_vars_post_load(void *opaque, int version_id)
uefi_vars_state *uv = opaque;
uefi_vars_update_storage(uv);
+ uefi_vars_json_save(uv);
uv->buffer = g_malloc(uv->buf_size);
return 0;
}
diff --git a/hw/uefi/var-service-json.c b/hw/uefi/var-service-json.c
index 761082c..ad3462c 100644
--- a/hw/uefi/var-service-json.c
+++ b/hw/uefi/var-service-json.c
@@ -178,7 +178,7 @@ void uefi_vars_json_init(uefi_vars_state *uv, Error **errp)
void uefi_vars_json_save(uefi_vars_state *uv)
{
- GString *gstr;
+ g_autoptr(GString) gstr = NULL;
int rc;
if (uv->jsonfd == -1) {
@@ -187,18 +187,25 @@ void uefi_vars_json_save(uefi_vars_state *uv)
gstr = uefi_vars_to_json(uv);
- lseek(uv->jsonfd, 0, SEEK_SET);
+ rc = lseek(uv->jsonfd, 0, SEEK_SET);
+ if (rc < 0) {
+ warn_report("%s: lseek error", __func__);
+ return;
+ }
+
rc = ftruncate(uv->jsonfd, 0);
if (rc != 0) {
warn_report("%s: ftruncate error", __func__);
+ return;
}
+
rc = write(uv->jsonfd, gstr->str, gstr->len);
if (rc != gstr->len) {
warn_report("%s: write error", __func__);
+ return;
}
- fsync(uv->jsonfd);
- g_string_free(gstr, true);
+ fsync(uv->jsonfd);
}
void uefi_vars_json_load(uefi_vars_state *uv, Error **errp)
@@ -207,7 +214,7 @@ void uefi_vars_json_load(uefi_vars_state *uv, Error **errp)
QObject *qobj;
Visitor *v;
char *str;
- size_t len;
+ ssize_t len;
int rc;
if (uv->jsonfd == -1) {
@@ -215,7 +222,12 @@ void uefi_vars_json_load(uefi_vars_state *uv, Error **errp)
}
len = lseek(uv->jsonfd, 0, SEEK_END);
+ if (len < 0) {
+ warn_report("%s: lseek error", __func__);
+ return;
+ }
if (len == 0) {
+ /* empty file */
return;
}
@@ -224,6 +236,8 @@ void uefi_vars_json_load(uefi_vars_state *uv, Error **errp)
rc = read(uv->jsonfd, str, len);
if (rc != len) {
warn_report("%s: read error", __func__);
+ g_free(str);
+ return;
}
str[len] = 0;
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
index 8260f1e..f808a01 100644
--- a/hw/xen/xen-bus.c
+++ b/hw/xen/xen-bus.c
@@ -353,10 +353,10 @@ static void xen_bus_realize(BusState *bus, Error **errp)
xs_node_watch(xenbus->xsh, node, key, xen_bus_backend_changed,
xenbus, &local_err);
if (local_err) {
- /* This need not be treated as a hard error so don't propagate */
- error_reportf_err(local_err,
- "failed to set up '%s' enumeration watch: ",
- type[i]);
+ warn_reportf_err(local_err,
+ "failed to set up '%s' enumeration watch: ",
+ type[i]);
+ local_err = NULL;
}
g_free(node);
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index 8cd6c00..47b1444 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -26,18 +26,6 @@
#include "exec/tswap.h"
#include "hw/core/cpu.h"
-/* some important defines:
- *
- * HOST_BIG_ENDIAN : whether the host cpu is big endian and
- * otherwise little endian.
- *
- * TARGET_BIG_ENDIAN : same for the target cpu
- */
-
-#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
-#define BSWAP_NEEDED
-#endif
-
/* Target-endianness CPU memory access functions. These fit into the
* {ld,st}{type}{sign}{size}{endian}_p naming scheme described in bswap.h.
*/
diff --git a/include/exec/poison.h b/include/exec/poison.h
index 8ed04b3..2c151fd 100644
--- a/include/exec/poison.h
+++ b/include/exec/poison.h
@@ -37,7 +37,6 @@
#pragma GCC poison TARGET_NAME
#pragma GCC poison TARGET_SUPPORTS_MTTCG
#pragma GCC poison TARGET_BIG_ENDIAN
-#pragma GCC poison BSWAP_NEEDED
#pragma GCC poison TARGET_LONG_BITS
#pragma GCC poison TARGET_FMT_lx
diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h
index 4fcaf3d..299ca9b 100644
--- a/include/hw/char/pl011.h
+++ b/include/hw/char/pl011.h
@@ -52,6 +52,11 @@ struct PL011State {
Clock *clk;
bool migrate_clk;
const unsigned char *id;
+ /*
+ * Since some users embed this struct directly, we must
+ * ensure that the C struct is at least as big as the Rust one.
+ */
+ uint8_t padding_for_rust[16];
};
DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr);
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 784a93d..d280dc3 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -190,7 +190,7 @@ ssize_t load_elf(const char *filename,
void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp);
ssize_t load_aout(const char *filename, hwaddr addr, int max_sz,
- int bswap_needed, hwaddr target_page_size);
+ bool big_endian, hwaddr target_page_size);
#define LOAD_UIMAGE_LOADADDR_INVALID (-1)
diff --git a/include/hw/ppc/pnv_pnor.h b/include/hw/ppc/pnv_pnor.h
index 19c2d64..b44cafe 100644
--- a/include/hw/ppc/pnv_pnor.h
+++ b/include/hw/ppc/pnv_pnor.h
@@ -28,6 +28,7 @@ struct PnvPnor {
BlockBackend *blk;
uint8_t *storage;
+ uint32_t lpc_address; /* Offset within LPC FW space */
int64_t size;
MemoryRegion mmio;
};
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 15fcec5..2c99856 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -52,6 +52,7 @@ extern const PropertyInfo qdev_prop_bool;
extern const PropertyInfo qdev_prop_uint8;
extern const PropertyInfo qdev_prop_uint16;
extern const PropertyInfo qdev_prop_uint32;
+extern const PropertyInfo qdev_prop_usize;
extern const PropertyInfo qdev_prop_int32;
extern const PropertyInfo qdev_prop_uint64;
extern const PropertyInfo qdev_prop_uint64_checkmask;
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 8799e4e..fa83d78 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -2121,7 +2121,7 @@ static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
memcpy(to, from, n);
}
-#ifdef BSWAP_NEEDED
+#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
static void bswap_ehdr(struct elfhdr *ehdr)
{
bswap16s(&ehdr->e_type); /* Object file type */
@@ -3143,7 +3143,7 @@ static bool parse_elf_properties(const ImageSource *src,
* The contents of a valid PT_GNU_PROPERTY is a sequence of uint32_t.
* Swap most of them now, beyond the header and namesz.
*/
-#ifdef BSWAP_NEEDED
+#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
for (int i = 4; i < n / 4; i++) {
bswap32s(note.data + i);
}
@@ -3999,7 +3999,7 @@ struct target_elf_prpsinfo {
char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
};
-#ifdef BSWAP_NEEDED
+#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
static void bswap_prstatus(struct target_elf_prstatus *prstatus)
{
prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo);
@@ -4038,7 +4038,7 @@ static void bswap_note(struct elf_note *en)
static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
static inline void bswap_note(struct elf_note *en) { }
-#endif /* BSWAP_NEEDED */
+#endif /* HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN */
/*
* Calculate file (dump) size of given memory region.
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 86d773a..5d22759 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -462,7 +462,7 @@ typedef struct {
abi_ulong sig[TARGET_NSIG_WORDS];
} target_sigset_t;
-#ifdef BSWAP_NEEDED
+#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
{
int i;
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
index 54d900b..ab33ce2 100644
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -94,7 +94,7 @@ ssize_t vmnet_receive_common(NetClientState *nc,
if_status = vmnet_write(s->vmnet_if, &packet, &pkt_cnt);
if (if_status != VMNET_SUCCESS) {
- error_report("vmnet: write error: %s\n",
+ error_report("vmnet: write error: %s",
vmnet_status_map_str(if_status));
return -1;
}
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index f137b49..bf88e0b 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -2,7 +2,7 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
-use std::{ffi::CStr, ptr::addr_of_mut};
+use std::{ffi::CStr, mem::size_of, ptr::addr_of_mut};
use qemu_api::{
chardev::{CharBackend, Chardev, Event},
@@ -12,6 +12,7 @@ use qemu_api::{
prelude::*,
qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property, ResetType, ResettablePhasesImpl},
qom::{ObjectImpl, Owned, ParentField},
+ static_assert,
sysbus::{SysBusDevice, SysBusDeviceImpl},
vmstate::VMStateDescription,
};
@@ -124,6 +125,12 @@ pub struct PL011State {
pub migrate_clock: bool,
}
+// Some C users of this device embed its state struct into their own
+// structs, so the size of the Rust version must not be any larger
+// than the size of the C one. If this assert triggers you need to
+// expand the padding_for_rust[] array in the C PL011State struct.
+static_assert!(size_of::<PL011State>() <= size_of::<qemu_api::bindings::PL011State>());
+
qom_isa!(PL011State : SysBusDevice, DeviceState, Object);
#[repr(C)]
diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs
index 0b2076d..b4d4a7e 100644
--- a/rust/hw/char/pl011/src/device_class.rs
+++ b/rust/hw/char/pl011/src/device_class.rs
@@ -8,8 +8,12 @@ use std::{
};
use qemu_api::{
- bindings::*, c_str, prelude::*, vmstate_clock, vmstate_fields, vmstate_of, vmstate_struct,
- vmstate_subsections, vmstate_unused, zeroable::Zeroable,
+ bindings::{qdev_prop_bool, qdev_prop_chr},
+ c_str,
+ prelude::*,
+ vmstate::VMStateDescription,
+ vmstate_clock, vmstate_fields, vmstate_of, vmstate_struct, vmstate_subsections, vmstate_unused,
+ zeroable::Zeroable,
};
use crate::device::{PL011Registers, PL011State};
diff --git a/rust/hw/timer/Kconfig b/rust/hw/timer/Kconfig
index 42e4213..afd9803 100644
--- a/rust/hw/timer/Kconfig
+++ b/rust/hw/timer/Kconfig
@@ -1,3 +1,2 @@
config X_HPET_RUST
bool
- default y if PC && HAVE_RUST
diff --git a/rust/hw/timer/hpet/src/hpet.rs b/rust/hw/timer/hpet/src/hpet.rs
index 20e0afd..3ae3ec2 100644
--- a/rust/hw/timer/hpet/src/hpet.rs
+++ b/rust/hw/timer/hpet/src/hpet.rs
@@ -12,7 +12,7 @@ use std::{
use qemu_api::{
bindings::{
address_space_memory, address_space_stl_le, qdev_prop_bit, qdev_prop_bool,
- qdev_prop_uint32, qdev_prop_uint8,
+ qdev_prop_uint32, qdev_prop_usize,
},
c_str,
cell::{BqlCell, BqlRefCell},
@@ -776,7 +776,7 @@ impl HPETState {
let timer_id: usize = ((addr - 0x100) / 0x20) as usize;
if timer_id <= self.num_timers.get() {
// TODO: Add trace point - trace_hpet_ram_[read|write]_timer_id(timer_id)
- TimerRegister::try_from(addr)
+ TimerRegister::try_from(addr & 0x18)
.map(|reg| HPETRegister::Timer(&self.timers[timer_id], reg))
} else {
// TODO: Add trace point - trace_hpet_timer_id_out_of_range(timer_id)
@@ -859,8 +859,8 @@ qemu_api::declare_properties! {
c_str!("timers"),
HPETState,
num_timers,
- unsafe { &qdev_prop_uint8 },
- u8,
+ unsafe { &qdev_prop_usize },
+ usize,
default = HPET_MIN_TIMERS
),
qemu_api::define_property!(
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index a3f226c..858685d 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -58,7 +58,8 @@ rust_qemu_api_objs = static_library(
libchardev.extract_all_objects(recursive: false),
libcrypto.extract_all_objects(recursive: false),
libauthz.extract_all_objects(recursive: false),
- libio.extract_all_objects(recursive: false)])
+ libio.extract_all_objects(recursive: false),
+ libmigration.extract_all_objects(recursive: false)])
rust_qemu_api_deps = declare_dependency(
dependencies: [
qom_ss.dependencies(),
@@ -71,7 +72,7 @@ rust_qemu_api_deps = declare_dependency(
test('rust-qemu-api-integration',
executable(
'rust-qemu-api-integration',
- 'tests/tests.rs',
+ files('tests/tests.rs', 'tests/vmstate_tests.rs'),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_args: ['--test'],
install: false,
diff --git a/rust/qemu-api/src/assertions.rs b/rust/qemu-api/src/assertions.rs
index 104dec3..eb12e94 100644
--- a/rust/qemu-api/src/assertions.rs
+++ b/rust/qemu-api/src/assertions.rs
@@ -91,6 +91,21 @@ macro_rules! assert_field_type {
}
};
};
+
+ ($t:ty, $i:tt, $ti:ty, num = $num:ident) => {
+ const _: () = {
+ #[allow(unused)]
+ fn assert_field_type(v: $t) {
+ fn types_must_be_equal<T, U>(_: T)
+ where
+ T: $crate::assertions::EqType<Itself = U>,
+ {
+ }
+ let index: usize = v.$num.try_into().unwrap();
+ types_must_be_equal::<_, &$ti>(&v.$i[index]);
+ }
+ };
+ };
}
/// Assert that an expression matches a pattern. This can also be
@@ -120,3 +135,25 @@ macro_rules! assert_match {
);
};
}
+
+/// Assert at compile time that an expression is true. This is similar
+/// to `const { assert!(...); }` but it works outside functions, as well as
+/// on versions of Rust before 1.79.
+///
+/// # Examples
+///
+/// ```
+/// # use qemu_api::static_assert;
+/// static_assert!("abc".len() == 3);
+/// ```
+///
+/// ```compile_fail
+/// # use qemu_api::static_assert;
+/// static_assert!("abc".len() == 2); // does not compile
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+ ($x:expr) => {
+ const _: () = assert!($x);
+ };
+}
diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
index f0510ae..1b2b12e 100644
--- a/rust/qemu-api/src/vmstate.rs
+++ b/rust/qemu-api/src/vmstate.rs
@@ -25,13 +25,11 @@
//! functionality that is missing from `vmstate_of!`.
use core::{marker::PhantomData, mem, ptr::NonNull};
+use std::os::raw::{c_int, c_void};
pub use crate::bindings::{VMStateDescription, VMStateField};
use crate::{
- bindings::{self, VMStateFlags},
- prelude::*,
- qom::Owned,
- zeroable::Zeroable,
+ bindings::VMStateFlags, callbacks::FnCall, prelude::*, qom::Owned, zeroable::Zeroable,
};
/// This macro is used to call a function with a generic argument bound
@@ -208,7 +206,7 @@ macro_rules! vmstate_of {
.as_bytes()
.as_ptr() as *const ::std::os::raw::c_char,
offset: $crate::offset_of!($struct_name, $field_name),
- $(.num_offset: $crate::offset_of!($struct_name, $num),)?
+ $(num_offset: $crate::offset_of!($struct_name, $num),)?
// The calls to `call_func_with_field!` are the magic that
// computes most of the VMStateField from the type of the field.
info: $crate::info_enum_to_ref!($crate::call_func_with_field!(
@@ -256,6 +254,10 @@ impl VMStateField {
if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 {
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0);
+ // VMS_ARRAY_OF_POINTER flag stores the size of pointer.
+ // FIXME: *const, *mut, NonNull and Box<> have the same size as usize.
+ // Resize if more smart pointers are supported.
+ self.size = std::mem::size_of::<usize>();
}
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0);
@@ -271,14 +273,21 @@ impl VMStateField {
}
#[must_use]
- pub const fn with_varray_flag<T: VMState>(mut self, flag: VMStateFlags) -> VMStateField {
- assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
+ pub const fn with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> VMStateField {
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0);
self.flags = VMStateFlags(self.flags.0 | flag.0);
+ self.num = 0; // varray uses num_offset instead of num.
self
}
#[must_use]
+ #[allow(unused_mut)]
+ pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> VMStateField {
+ assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
+ self.with_varray_flag_unchecked(flag)
+ }
+
+ #[must_use]
pub const fn with_varray_multiply(mut self, num: u32) -> VMStateField {
assert!(num <= 0x7FFF_FFFFu32);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0);
@@ -333,6 +342,7 @@ impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState);
impl_vmstate_transparent!(std::pin::Pin<T> where T: VMState);
impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState);
impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState);
+impl_vmstate_transparent!(crate::cell::Opaque<T> where T: VMState);
#[macro_export]
macro_rules! impl_vmstate_bitsized {
@@ -379,7 +389,7 @@ impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8);
impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16);
impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32);
impl_vmstate_scalar!(vmstate_info_uint64, u64);
-impl_vmstate_scalar!(vmstate_info_timer, bindings::QEMUTimer);
+impl_vmstate_scalar!(vmstate_info_timer, crate::timer::Timer);
// Pointer types using the underlying type's VMState plus VMS_POINTER
// Note that references are not supported, though references to cells
@@ -440,21 +450,23 @@ macro_rules! vmstate_struct {
name: ::core::concat!(::core::stringify!($field_name), "\0")
.as_bytes()
.as_ptr() as *const ::std::os::raw::c_char,
- $(.num_offset: $crate::offset_of!($struct_name, $num),)?
+ $(num_offset: $crate::offset_of!($struct_name, $num),)?
offset: {
- $crate::assert_field_type!($struct_name, $field_name, $type);
+ $crate::assert_field_type!($struct_name, $field_name, $type $(, num = $num)?);
$crate::offset_of!($struct_name, $field_name)
},
size: ::core::mem::size_of::<$type>(),
flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
- vmsd: unsafe { $vmsd },
- ..$crate::zeroable::Zeroable::ZERO $(
- .with_varray_flag($crate::call_func_with_field!(
- $crate::vmstate::vmstate_varray_flag,
- $struct_name,
- $num))
- $(.with_varray_multiply($factor))?)?
- }
+ vmsd: $vmsd,
+ ..$crate::zeroable::Zeroable::ZERO
+ } $(.with_varray_flag_unchecked(
+ $crate::call_func_with_field!(
+ $crate::vmstate::vmstate_varray_flag,
+ $struct_name,
+ $num
+ )
+ )
+ $(.with_varray_multiply($factor))?)?
};
}
@@ -475,7 +487,10 @@ macro_rules! vmstate_clock {
$crate::offset_of!($struct_name, $field_name)
},
size: ::core::mem::size_of::<*const $crate::qdev::Clock>(),
- flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0),
+ flags: $crate::bindings::VMStateFlags(
+ $crate::bindings::VMStateFlags::VMS_STRUCT.0
+ | $crate::bindings::VMStateFlags::VMS_POINTER.0,
+ ),
vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_clock) },
..$crate::zeroable::Zeroable::ZERO
}
@@ -499,6 +514,53 @@ macro_rules! vmstate_fields {
}}
}
+pub extern "C" fn rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>(
+ opaque: *mut c_void,
+ version_id: c_int,
+) -> bool {
+ let owner: &T = unsafe { &*(opaque.cast::<T>()) };
+ let version: u8 = version_id.try_into().unwrap();
+ // SAFETY: the opaque was passed as a reference to `T`.
+ F::call((owner, version))
+}
+
+pub type VMSFieldExistCb = unsafe extern "C" fn(
+ opaque: *mut std::os::raw::c_void,
+ version_id: std::os::raw::c_int,
+) -> bool;
+
+#[doc(alias = "VMSTATE_VALIDATE")]
+#[macro_export]
+macro_rules! vmstate_validate {
+ ($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => {
+ $crate::bindings::VMStateField {
+ name: ::std::ffi::CStr::as_ptr($test_name),
+ field_exists: {
+ const fn test_cb_builder__<
+ T,
+ F: for<'a> $crate::callbacks::FnCall<(&'a T, u8), bool>,
+ >(
+ _phantom: ::core::marker::PhantomData<F>,
+ ) -> $crate::vmstate::VMSFieldExistCb {
+ let _: () = F::ASSERT_IS_SOME;
+ $crate::vmstate::rust_vms_test_field_exists::<T, F>
+ }
+
+ const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> {
+ ::core::marker::PhantomData
+ }
+ Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn)))
+ },
+ flags: $crate::bindings::VMStateFlags(
+ $crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
+ | $crate::bindings::VMStateFlags::VMS_ARRAY.0,
+ ),
+ num: 0, // 0 elements: no data, only run test_fn callback
+ ..$crate::zeroable::Zeroable::ZERO
+ }
+ };
+}
+
/// A transparent wrapper type for the `subsections` field of
/// [`VMStateDescription`].
///
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index 269122e..99a7aab 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -17,6 +17,8 @@ use qemu_api::{
zeroable::Zeroable,
};
+mod vmstate_tests;
+
// Test that macros can compile.
pub static VMSTATE: VMStateDescription = VMStateDescription {
name: c_str!("name").as_ptr(),
diff --git a/rust/qemu-api/tests/vmstate_tests.rs b/rust/qemu-api/tests/vmstate_tests.rs
new file mode 100644
index 0000000..b8d8b45
--- /dev/null
+++ b/rust/qemu-api/tests/vmstate_tests.rs
@@ -0,0 +1,477 @@
+// Copyright (C) 2025 Intel Corporation.
+// Author(s): Zhao Liu <zhai1.liu@intel.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use std::{ffi::CStr, mem::size_of, os::raw::c_void, ptr::NonNull, slice};
+
+use qemu_api::{
+ bindings::{
+ vmstate_info_bool, vmstate_info_int32, vmstate_info_int64, vmstate_info_int8,
+ vmstate_info_uint64, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags,
+ },
+ c_str,
+ cell::{BqlCell, Opaque},
+ impl_vmstate_forward,
+ vmstate::{VMStateDescription, VMStateField},
+ vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused, vmstate_validate,
+ zeroable::Zeroable,
+};
+
+const FOO_ARRAY_MAX: usize = 3;
+
+// =========================== Test VMSTATE_FOOA ===========================
+// Test the use cases of the vmstate macro, corresponding to the following C
+// macro variants:
+// * VMSTATE_FOOA:
+// - VMSTATE_U16
+// - VMSTATE_UNUSED
+// - VMSTATE_VARRAY_UINT16_UNSAFE
+// - VMSTATE_VARRAY_MULTIPLY
+#[repr(C)]
+#[derive(qemu_api_macros::offsets)]
+struct FooA {
+ arr: [u8; FOO_ARRAY_MAX],
+ num: u16,
+ arr_mul: [i8; FOO_ARRAY_MAX],
+ num_mul: u32,
+ elem: i8,
+}
+
+static VMSTATE_FOOA: VMStateDescription = VMStateDescription {
+ name: c_str!("foo_a").as_ptr(),
+ version_id: 1,
+ minimum_version_id: 1,
+ fields: vmstate_fields! {
+ vmstate_of!(FooA, elem),
+ vmstate_unused!(size_of::<i64>()),
+ vmstate_of!(FooA, arr[0 .. num]).with_version_id(0),
+ vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]),
+ },
+ ..Zeroable::ZERO
+};
+
+#[test]
+fn test_vmstate_uint16() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
+
+ // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
+ b"elem\0"
+ );
+ assert_eq!(foo_fields[0].offset, 16);
+ assert_eq!(foo_fields[0].num_offset, 0);
+ assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 });
+ assert_eq!(foo_fields[0].version_id, 0);
+ assert_eq!(foo_fields[0].size, 1);
+ assert_eq!(foo_fields[0].num, 0);
+ assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
+ assert!(foo_fields[0].vmsd.is_null());
+ assert!(foo_fields[0].field_exists.is_none());
+}
+
+#[test]
+fn test_vmstate_unused() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
+
+ // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
+ b"unused\0"
+ );
+ assert_eq!(foo_fields[1].offset, 0);
+ assert_eq!(foo_fields[1].num_offset, 0);
+ assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer });
+ assert_eq!(foo_fields[1].version_id, 0);
+ assert_eq!(foo_fields[1].size, 8);
+ assert_eq!(foo_fields[1].num, 0);
+ assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER);
+ assert!(foo_fields[1].vmsd.is_null());
+ assert!(foo_fields[1].field_exists.is_none());
+}
+
+#[test]
+fn test_vmstate_varray_uint16_unsafe() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
+
+ // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to
+ // VMSTATE_VARRAY_UINT16_UNSAFE)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
+ b"arr\0"
+ );
+ assert_eq!(foo_fields[2].offset, 0);
+ assert_eq!(foo_fields[2].num_offset, 4);
+ assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
+ assert_eq!(foo_fields[2].version_id, 0);
+ assert_eq!(foo_fields[2].size, 1);
+ assert_eq!(foo_fields[2].num, 0);
+ assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16);
+ assert!(foo_fields[2].vmsd.is_null());
+ assert!(foo_fields[2].field_exists.is_none());
+}
+
+#[test]
+fn test_vmstate_varray_multiply() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
+
+ // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to
+ // VMSTATE_VARRAY_MULTIPLY)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
+ b"arr_mul\0"
+ );
+ assert_eq!(foo_fields[3].offset, 6);
+ assert_eq!(foo_fields[3].num_offset, 12);
+ assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 });
+ assert_eq!(foo_fields[3].version_id, 0);
+ assert_eq!(foo_fields[3].size, 1);
+ assert_eq!(foo_fields[3].num, 16);
+ assert_eq!(
+ foo_fields[3].flags.0,
+ VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
+ );
+ assert!(foo_fields[3].vmsd.is_null());
+ assert!(foo_fields[3].field_exists.is_none());
+
+ // The last VMStateField in VMSTATE_FOOA.
+ assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
+}
+
+// =========================== Test VMSTATE_FOOB ===========================
+// Test the use cases of the vmstate macro, corresponding to the following C
+// macro variants:
+// * VMSTATE_FOOB:
+// - VMSTATE_BOOL_V
+// - VMSTATE_U64
+// - VMSTATE_STRUCT_VARRAY_UINT8
+// - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32
+// - VMSTATE_ARRAY
+#[repr(C)]
+#[derive(qemu_api_macros::offsets)]
+struct FooB {
+ arr_a: [FooA; FOO_ARRAY_MAX],
+ num_a: u8,
+ arr_a_mul: [FooA; FOO_ARRAY_MAX],
+ num_a_mul: u32,
+ wrap: BqlCell<u64>,
+ val: bool,
+ // FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test.
+ arr_i64: [i64; FOO_ARRAY_MAX],
+}
+
+static VMSTATE_FOOB: VMStateDescription = VMStateDescription {
+ name: c_str!("foo_b").as_ptr(),
+ version_id: 2,
+ minimum_version_id: 1,
+ fields: vmstate_fields! {
+ vmstate_of!(FooB, val).with_version_id(2),
+ vmstate_of!(FooB, wrap),
+ vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1),
+ vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2),
+ vmstate_of!(FooB, arr_i64),
+ },
+ ..Zeroable::ZERO
+};
+
+#[test]
+fn test_vmstate_bool_v() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
+
+ // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
+ b"val\0"
+ );
+ assert_eq!(foo_fields[0].offset, 136);
+ assert_eq!(foo_fields[0].num_offset, 0);
+ assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_bool });
+ assert_eq!(foo_fields[0].version_id, 2);
+ assert_eq!(foo_fields[0].size, 1);
+ assert_eq!(foo_fields[0].num, 0);
+ assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
+ assert!(foo_fields[0].vmsd.is_null());
+ assert!(foo_fields[0].field_exists.is_none());
+}
+
+#[test]
+fn test_vmstate_uint64() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
+
+ // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
+ b"wrap\0"
+ );
+ assert_eq!(foo_fields[1].offset, 128);
+ assert_eq!(foo_fields[1].num_offset, 0);
+ assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_uint64 });
+ assert_eq!(foo_fields[1].version_id, 0);
+ assert_eq!(foo_fields[1].size, 8);
+ assert_eq!(foo_fields[1].num, 0);
+ assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_SINGLE);
+ assert!(foo_fields[1].vmsd.is_null());
+ assert!(foo_fields[1].field_exists.is_none());
+}
+
+#[test]
+fn test_vmstate_struct_varray_uint8() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
+
+ // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to
+ // VMSTATE_STRUCT_VARRAY_UINT8)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
+ b"arr_a\0"
+ );
+ assert_eq!(foo_fields[2].offset, 0);
+ assert_eq!(foo_fields[2].num_offset, 60);
+ assert!(foo_fields[2].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
+ assert_eq!(foo_fields[2].version_id, 1);
+ assert_eq!(foo_fields[2].size, 20);
+ assert_eq!(foo_fields[2].num, 0);
+ assert_eq!(
+ foo_fields[2].flags.0,
+ VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0
+ );
+ assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA);
+ assert!(foo_fields[2].field_exists.is_none());
+}
+
+#[test]
+fn test_vmstate_struct_varray_uint32_multiply() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
+
+ // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to
+ // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
+ b"arr_a_mul\0"
+ );
+ assert_eq!(foo_fields[3].offset, 64);
+ assert_eq!(foo_fields[3].num_offset, 124);
+ assert!(foo_fields[3].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
+ assert_eq!(foo_fields[3].version_id, 2);
+ assert_eq!(foo_fields[3].size, 20);
+ assert_eq!(foo_fields[3].num, 32);
+ assert_eq!(
+ foo_fields[3].flags.0,
+ VMStateFlags::VMS_STRUCT.0
+ | VMStateFlags::VMS_VARRAY_UINT32.0
+ | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
+ );
+ assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA);
+ assert!(foo_fields[3].field_exists.is_none());
+}
+
+#[test]
+fn test_vmstate_macro_array() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
+
+ // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to
+ // VMSTATE_ARRAY)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[4].name) }.to_bytes_with_nul(),
+ b"arr_i64\0"
+ );
+ assert_eq!(foo_fields[4].offset, 144);
+ assert_eq!(foo_fields[4].num_offset, 0);
+ assert_eq!(foo_fields[4].info, unsafe { &vmstate_info_int64 });
+ assert_eq!(foo_fields[4].version_id, 0);
+ assert_eq!(foo_fields[4].size, 8);
+ assert_eq!(foo_fields[4].num, FOO_ARRAY_MAX as i32);
+ assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY);
+ assert!(foo_fields[4].vmsd.is_null());
+ assert!(foo_fields[4].field_exists.is_none());
+
+ // The last VMStateField in VMSTATE_FOOB.
+ assert_eq!(foo_fields[5].flags, VMStateFlags::VMS_END);
+}
+
+// =========================== Test VMSTATE_FOOC ===========================
+// Test the use cases of the vmstate macro, corresponding to the following C
+// macro variants:
+// * VMSTATE_FOOC:
+// - VMSTATE_POINTER
+// - VMSTATE_ARRAY_OF_POINTER
+struct FooCWrapper([Opaque<*mut u8>; FOO_ARRAY_MAX]); // Though Opaque<> array is almost impossible.
+
+impl_vmstate_forward!(FooCWrapper);
+
+#[repr(C)]
+#[derive(qemu_api_macros::offsets)]
+struct FooC {
+ ptr: *const i32,
+ ptr_a: NonNull<FooA>,
+ arr_ptr: [Box<u8>; FOO_ARRAY_MAX],
+ arr_ptr_wrap: FooCWrapper,
+}
+
+static VMSTATE_FOOC: VMStateDescription = VMStateDescription {
+ name: c_str!("foo_c").as_ptr(),
+ version_id: 3,
+ minimum_version_id: 1,
+ fields: vmstate_fields! {
+ vmstate_of!(FooC, ptr).with_version_id(2),
+ // FIXME: Currently vmstate_struct doesn't support the pointer to structure.
+ // VMSTATE_STRUCT_POINTER: vmstate_struct!(FooC, ptr_a, VMSTATE_FOOA, NonNull<FooA>)
+ vmstate_unused!(size_of::<NonNull<FooA>>()),
+ vmstate_of!(FooC, arr_ptr),
+ vmstate_of!(FooC, arr_ptr_wrap),
+ },
+ ..Zeroable::ZERO
+};
+
+const PTR_SIZE: usize = size_of::<*mut ()>();
+
+#[test]
+fn test_vmstate_pointer() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
+
+ // 1st VMStateField ("ptr") in VMSTATE_FOOC (corresponding to VMSTATE_POINTER)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
+ b"ptr\0"
+ );
+ assert_eq!(foo_fields[0].offset, 0);
+ assert_eq!(foo_fields[0].num_offset, 0);
+ assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int32 });
+ assert_eq!(foo_fields[0].version_id, 2);
+ assert_eq!(foo_fields[0].size, 4);
+ assert_eq!(foo_fields[0].num, 0);
+ assert_eq!(
+ foo_fields[0].flags.0,
+ VMStateFlags::VMS_SINGLE.0 | VMStateFlags::VMS_POINTER.0
+ );
+ assert!(foo_fields[0].vmsd.is_null());
+ assert!(foo_fields[0].field_exists.is_none());
+}
+
+#[test]
+fn test_vmstate_macro_array_of_pointer() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
+
+ // 3rd VMStateField ("arr_ptr") in VMSTATE_FOOC (corresponding to
+ // VMSTATE_ARRAY_OF_POINTER)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
+ b"arr_ptr\0"
+ );
+ assert_eq!(foo_fields[2].offset, 2 * PTR_SIZE);
+ assert_eq!(foo_fields[2].num_offset, 0);
+ assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
+ assert_eq!(foo_fields[2].version_id, 0);
+ assert_eq!(foo_fields[2].size, PTR_SIZE);
+ assert_eq!(foo_fields[2].num, FOO_ARRAY_MAX as i32);
+ assert_eq!(
+ foo_fields[2].flags.0,
+ VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
+ );
+ assert!(foo_fields[2].vmsd.is_null());
+ assert!(foo_fields[2].field_exists.is_none());
+}
+
+#[test]
+fn test_vmstate_macro_array_of_pointer_wrapped() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
+
+ // 4th VMStateField ("arr_ptr_wrap") in VMSTATE_FOOC (corresponding to
+ // VMSTATE_ARRAY_OF_POINTER)
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
+ b"arr_ptr_wrap\0"
+ );
+ assert_eq!(foo_fields[3].offset, (FOO_ARRAY_MAX + 2) * PTR_SIZE);
+ assert_eq!(foo_fields[3].num_offset, 0);
+ assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
+ assert_eq!(foo_fields[3].version_id, 0);
+ assert_eq!(foo_fields[3].size, PTR_SIZE);
+ assert_eq!(foo_fields[3].num, FOO_ARRAY_MAX as i32);
+ assert_eq!(
+ foo_fields[2].flags.0,
+ VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
+ );
+ assert!(foo_fields[3].vmsd.is_null());
+ assert!(foo_fields[3].field_exists.is_none());
+
+ // The last VMStateField in VMSTATE_FOOC.
+ assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
+}
+
+// =========================== Test VMSTATE_FOOD ===========================
+// Test the use cases of the vmstate macro, corresponding to the following C
+// macro variants:
+// * VMSTATE_FOOD:
+// - VMSTATE_VALIDATE
+
+// Add more member fields when vmstate_of/vmstate_struct support "test"
+// parameter.
+struct FooD;
+
+impl FooD {
+ fn validate_food_0(&self, _version_id: u8) -> bool {
+ true
+ }
+
+ fn validate_food_1(_state: &FooD, _version_id: u8) -> bool {
+ false
+ }
+}
+
+fn validate_food_2(_state: &FooD, _version_id: u8) -> bool {
+ true
+}
+
+static VMSTATE_FOOD: VMStateDescription = VMStateDescription {
+ name: c_str!("foo_d").as_ptr(),
+ version_id: 3,
+ minimum_version_id: 1,
+ fields: vmstate_fields! {
+ vmstate_validate!(FooD, c_str!("foo_d_0"), FooD::validate_food_0),
+ vmstate_validate!(FooD, c_str!("foo_d_1"), FooD::validate_food_1),
+ vmstate_validate!(FooD, c_str!("foo_d_2"), validate_food_2),
+ },
+ ..Zeroable::ZERO
+};
+
+#[test]
+fn test_vmstate_validate() {
+ let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOD.fields, 4) };
+ let mut foo_d = FooD;
+ let foo_d_p = std::ptr::addr_of_mut!(foo_d).cast::<c_void>();
+
+ // 1st VMStateField in VMSTATE_FOOD
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
+ b"foo_d_0\0"
+ );
+ assert_eq!(foo_fields[0].offset, 0);
+ assert_eq!(foo_fields[0].num_offset, 0);
+ assert!(foo_fields[0].info.is_null());
+ assert_eq!(foo_fields[0].version_id, 0);
+ assert_eq!(foo_fields[0].size, 0);
+ assert_eq!(foo_fields[0].num, 0);
+ assert_eq!(
+ foo_fields[0].flags.0,
+ VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_MUST_EXIST.0
+ );
+ assert!(foo_fields[0].vmsd.is_null());
+ assert!(unsafe { foo_fields[0].field_exists.unwrap()(foo_d_p, 0) });
+
+ // 2nd VMStateField in VMSTATE_FOOD
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
+ b"foo_d_1\0"
+ );
+ assert!(!unsafe { foo_fields[1].field_exists.unwrap()(foo_d_p, 1) });
+
+ // 3rd VMStateField in VMSTATE_FOOD
+ assert_eq!(
+ unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
+ b"foo_d_2\0"
+ );
+ assert!(unsafe { foo_fields[2].field_exists.unwrap()(foo_d_p, 2) });
+
+ // The last VMStateField in VMSTATE_FOOD.
+ assert_eq!(foo_fields[3].flags, VMStateFlags::VMS_END);
+}
diff --git a/rust/wrapper.h b/rust/wrapper.h
index d927ad6..d4fec54 100644
--- a/rust/wrapper.h
+++ b/rust/wrapper.h
@@ -65,3 +65,4 @@ typedef enum memory_order {
#include "exec/memattrs.h"
#include "qemu/timer.h"
#include "exec/address-spaces.h"
+#include "hw/char/pl011.h"
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 1cd959a..9fdc305 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -43,7 +43,7 @@ enum {
TLBRET_PE = 7,
};
-bool check_ps(CPULoongArchState *ent, int ps);
+bool check_ps(CPULoongArchState *ent, uint8_t ps);
extern const VMStateDescription vmstate_loongarch_cpu;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 28735c8..7f63e7c 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1081,7 +1081,6 @@ int kvm_arch_init_vcpu(CPUState *cs)
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)) {
@@ -1091,29 +1090,34 @@ int kvm_arch_init_vcpu(CPUState *cs)
ret = kvm_cpu_check_lsx(cs, &local_err);
if (ret < 0) {
error_report_err(local_err);
+ return ret;
}
ret = kvm_cpu_check_lasx(cs, &local_err);
if (ret < 0) {
error_report_err(local_err);
+ return ret;
}
ret = kvm_cpu_check_lbt(cs, &local_err);
if (ret < 0) {
error_report_err(local_err);
+ return ret;
}
ret = kvm_cpu_check_pmu(cs, &local_err);
if (ret < 0) {
error_report_err(local_err);
+ return ret;
}
ret = kvm_cpu_check_pv_features(cs, &local_err);
if (ret < 0) {
error_report_err(local_err);
+ return ret;
}
- return ret;
+ return 0;
}
static bool loongarch_get_lbt(Object *obj, Error **errp)
diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c
index 379c71e..6a7a65c 100644
--- a/target/loongarch/tcg/csr_helper.c
+++ b/target/loongarch/tcg/csr_helper.c
@@ -115,7 +115,7 @@ target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val)
target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val)
{
- int shift, ptbase;
+ uint8_t shift, ptbase;
int64_t old_v = env->CSR_PWCL;
/*
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index 646dbf5..70d1b5c 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -19,12 +19,12 @@
#include "exec/log.h"
#include "cpu-csr.h"
-bool check_ps(CPULoongArchState *env, int tlb_ps)
+bool check_ps(CPULoongArchState *env, uint8_t tlb_ps)
{
- if (tlb_ps > 64) {
- return false;
- }
- return BIT_ULL(tlb_ps) & (env->CSR_PRCFG2);
+ if (tlb_ps >= 64) {
+ return false;
+ }
+ return BIT_ULL(tlb_ps) & (env->CSR_PRCFG2);
}
void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
@@ -543,7 +543,7 @@ 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;
+ target_ulong badvaddr, index, phys;
uint64_t dir_base, dir_width;
if (unlikely((level == 0) || (level > 4))) {
@@ -571,8 +571,7 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
get_dir_base_width(env, &dir_base, &dir_width, level);
index = (badvaddr >> dir_base) & ((1 << dir_width) - 1);
phys = base | index << 3;
- ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
- return ret;
+ return ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
}
void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index efab54a..3ee8351 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1356,6 +1356,17 @@ struct CPUArchState {
* special way (such as routing some resume causes to 0x100, i.e. sreset).
*/
bool resume_as_sreset;
+
+ /*
+ * On powernv, quiesced means the CPU has been stopped using PC direct
+ * control xscom registers.
+ *
+ * On spapr, quiesced means it is in the "RTAS stopped" state.
+ *
+ * The core halted/stopped variables aren't sufficient for this, because
+ * they can be changed with various side-band operations like qmp cont,
+ * powersave interrupts, etc.
+ */
bool quiesced;
#endif
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 8b590e7..7decc09 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -2744,14 +2744,6 @@ static void init_proc_e200(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000); /* TOFIX */
- spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- spr_register(env, SPR_BOOKE_DSRR1, "DSRR1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
init_tlbs_emb(env);
init_excp_e200(env, 0xFFFF0000UL);
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 44e19aa..c941c89 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1951,6 +1951,10 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
target_ulong lpcr = env->spr[SPR_LPCR];
bool async_deliver;
+ if (unlikely(env->quiesced)) {
+ return 0;
+ }
+
#ifdef TARGET_PPC64
switch (env->excp_model) {
case POWERPC_EXCP_POWER7:
diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc
index 70d0ad2..92d6e8c 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -994,8 +994,8 @@ static bool do_vector_rotl_quad(DisasContext *ctx, arg_VX *a, bool mask,
{
TCGv_i64 ah, al, vrb, n, t0, t1, zero = tcg_constant_i64(0);
- REQUIRE_VECTOR(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA310);
+ REQUIRE_VECTOR(ctx);
ah = tcg_temp_new_i64();
al = tcg_temp_new_i64();
diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc
index a869f30..00ad57c 100644
--- a/target/ppc/translate/vsx-impl.c.inc
+++ b/target/ppc/translate/vsx-impl.c.inc
@@ -61,8 +61,8 @@ static bool trans_LXVD2X(DisasContext *ctx, arg_LXVD2X *a)
TCGv EA;
TCGv_i64 t0;
- REQUIRE_VSX(ctx);
REQUIRE_INSNS_FLAGS2(ctx, VSX);
+ REQUIRE_VSX(ctx);
t0 = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
@@ -80,8 +80,8 @@ static bool trans_LXVW4X(DisasContext *ctx, arg_LXVW4X *a)
TCGv EA;
TCGv_i64 xth, xtl;
- REQUIRE_VSX(ctx);
REQUIRE_INSNS_FLAGS2(ctx, VSX);
+ REQUIRE_VSX(ctx);
xth = tcg_temp_new_i64();
xtl = tcg_temp_new_i64();
@@ -113,12 +113,12 @@ static bool trans_LXVWSX(DisasContext *ctx, arg_LXVWSX *a)
TCGv EA;
TCGv_i32 data;
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
if (a->rt < 32) {
REQUIRE_VSX(ctx);
} else {
REQUIRE_VECTOR(ctx);
}
- REQUIRE_INSNS_FLAGS2(ctx, ISA300);
gen_set_access_type(ctx, ACCESS_INT);
EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
@@ -133,8 +133,8 @@ static bool trans_LXVDSX(DisasContext *ctx, arg_LXVDSX *a)
TCGv EA;
TCGv_i64 data;
- REQUIRE_VSX(ctx);
REQUIRE_INSNS_FLAGS2(ctx, VSX);
+ REQUIRE_VSX(ctx);
gen_set_access_type(ctx, ACCESS_INT);
EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
@@ -185,8 +185,8 @@ static bool trans_LXVH8X(DisasContext *ctx, arg_LXVH8X *a)
TCGv EA;
TCGv_i64 xth, xtl;
- REQUIRE_VSX(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_VSX(ctx);
xth = tcg_temp_new_i64();
xtl = tcg_temp_new_i64();
@@ -208,8 +208,8 @@ static bool trans_LXVB16X(DisasContext *ctx, arg_LXVB16X *a)
TCGv EA;
TCGv_i128 data;
- REQUIRE_VSX(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_VSX(ctx);
data = tcg_temp_new_i128();
gen_set_access_type(ctx, ACCESS_INT);
@@ -312,8 +312,8 @@ static bool trans_STXVD2X(DisasContext *ctx, arg_STXVD2X *a)
TCGv EA;
TCGv_i64 t0;
- REQUIRE_VSX(ctx);
REQUIRE_INSNS_FLAGS2(ctx, VSX);
+ REQUIRE_VSX(ctx);
t0 = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
@@ -331,8 +331,8 @@ static bool trans_STXVW4X(DisasContext *ctx, arg_STXVW4X *a)
TCGv EA;
TCGv_i64 xsh, xsl;
- REQUIRE_VSX(ctx);
REQUIRE_INSNS_FLAGS2(ctx, VSX);
+ REQUIRE_VSX(ctx);
xsh = tcg_temp_new_i64();
xsl = tcg_temp_new_i64();
@@ -364,8 +364,8 @@ static bool trans_STXVH8X(DisasContext *ctx, arg_STXVH8X *a)
TCGv EA;
TCGv_i64 xsh, xsl;
- REQUIRE_VSX(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_VSX(ctx);
xsh = tcg_temp_new_i64();
xsl = tcg_temp_new_i64();
@@ -394,8 +394,8 @@ static bool trans_STXVB16X(DisasContext *ctx, arg_STXVB16X *a)
TCGv EA;
TCGv_i128 data;
- REQUIRE_VSX(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_VSX(ctx);
data = tcg_temp_new_i128();
gen_set_access_type(ctx, ACCESS_INT);
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 5a8c1f1..3136d15 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -103,8 +103,7 @@ qtests_i386 = \
config_all_devices.has_key('CONFIG_VIRTIO_PCI') and \
slirp.found() ? ['virtio-net-failover'] : []) + \
(unpack_edk2_blobs and \
- (config_all_devices.has_key('CONFIG_HPET') or \
- config_all_devices.has_key('CONFIG_X_HPET_RUST')) and \
+ config_all_devices.has_key('CONFIG_HPET') and \
config_all_devices.has_key('CONFIG_PARALLEL') ? ['bios-tables-test'] : []) + \
qtests_pci + \
qtests_cxl + \