Merge tag 'pull-misc-2026-07-14' of https://repo.or.cz/qemu/armbru into staging Miscellaneous patches for 2026-07-14 # -----BEGIN PGP SIGNATURE----- # # iQJGBAABCgAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmpV/gsSHGFybWJydUBy # ZWRoYXQuY29tAAoJEDhwtADrkYZTi/oP/1B9i3crkWVFgzZ3YyvDFG5aAPtMZ4MU # TFEh3xKtzOMIu/jvFvapSNAHG/4kPuiHTJXsi8VYtvzoKhhJggczSJI1K3JSxEtg # 8j7RVKevIwEk3kBR4+L3yegGerNJd2cFfyJLK6DzljxqwRd1bo6/iigxwrg5WzG6 # YDyPqeOtrOBVDjjRXH5T1k+rL5HgmUp5JQWsc+gZSqdVSLWPnTEOtg1Xs1ipEIRm # JRiKG/5ADwao8Ml6iGmmQQsFvNe6EYWbm6NGdavzuD7mp6Roxuq4CtxD+6jT3roK # GxQKsig2Un2vBWgvI9ZokwULcpB4esiUAvz9pPYg9WZB/PXi24Fjivhjm2w69E8N # QIU1TimQFkR0nIFkChYPAfQvBbzdTGv71dZ4/vxVI5ha7kAYw3xWMAGuMhX4FivW # mEGu7j999IlRSWZYBLUsbsBCM4gXuxzPjs9Cp8xghLi9mnF+MITz0zCHKx2FQwE7 # 06yTeEvjPe8LWqx6mfeFq/k4c+Hpiib+D4cOyIBLqldGjFowbaaTmLP8W6VUGM07 # QsuPIE0Py9EOBwOXqYTYrv/SsBLPp03j3Om/P4Bo6E3Zhms0gF8+WXACyJX1t1H0 # V+GtgloccjgfP9hynHa5RaoFeDxOZwksV6cxbuWm38yhhcyaq0iZMXqGWjfO4h5f # HgNAI8X660MA # =fEwp # -----END PGP SIGNATURE----- # gpg: Signature made Tue 14 Jul 2026 10:14:51 BST # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * tag 'pull-misc-2026-07-14' of https://repo.or.cz/qemu/armbru: json-parser: fix formatting of comment MAINTAINERS: Regularise the status fields (again) qom: Fix device-list-properties & friends to show legacy-FOO props qapi: Fix misspelled section tags in doc comments Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
diff --git a/.mailmap b/.mailmap index 593b6c2..e5dc644 100644 --- a/.mailmap +++ b/.mailmap
@@ -36,9 +36,11 @@ Marek Dolata <mkdolata@us.ibm.com> mkdolata@us.ibm.com <mkdolata@us.ibm.com> Michael Ellerman <mpe@ellerman.id.au> michael@ozlabs.org <michael@ozlabs.org> Nick Hudson <hnick@vmware.com> hnick@vmware.com <hnick@vmware.com> +Ryan Zhang <ryan.zhang@nxp.com> Ryan Zhang <mailto> Timothée Cocault <timothee.cocault@gmail.com> timothee.cocault@gmail.com <timothee.cocault@gmail.com> Stefan Weil <sw@weilnetz.de> <weil@mail.berlios.de> Stefan Weil <sw@weilnetz.de> Stefan Weil <stefan@kiwi.(none)> +Zhongyao Chen <chen.zhongyao@zte.com.cn> chen.zhongyao@zte.com.cn <chen.zhongyao@zte.com.cn> # There is also a: # (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162> @@ -122,6 +124,7 @@ Song Gao <17746591750@163.com> <gaosong@loongson.cn> Taylor Simpson <ltaylorsimpson@gmail.com> <tsimpson@quicinc.com> Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com> +Alexander Mikhalitsyn <alexander@mihalicyn.com> <aleksandr.mikhalitsyn@futurfusion.io> # Also list preferred name forms where people have changed their # git author config, or had utf8/latin1 encoding issues.
diff --git a/MAINTAINERS b/MAINTAINERS index 8f84f3c..6ea4db6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS
@@ -1760,8 +1760,10 @@ F: tests/tcg/riscv64/test-crc32.S Microchip PolarFire SoC Icicle Kit +M: Conor Dooley <conor@kernel.org> +M: Sebastian Huber <sebastian.huber@embedded-brains.de> L: qemu-riscv@nongnu.org -S: Supported +S: Odd Fixes F: docs/system/riscv/microchip-icicle-kit.rst F: hw/riscv/microchip_pfsoc.c F: hw/char/mchp_pfsoc_mmuart.c @@ -1828,6 +1830,7 @@ F: hw/watchdog/k230_wdt.c F: include/hw/riscv/k230.h F: include/hw/watchdog/k230_wdt.h +F: tests/functional/riscv64/test_k230.py F: tests/qtest/k230-wdt-test.c RX Machines @@ -4611,7 +4614,7 @@ M: Alex Bennée <alex.bennee@linaro.org> S: Odd Fixes F: gitdm.config -F: contrib/gitdm/* +F: scripts/gitdm/* Incompatible changes L: devel@lists.libvirt.org
diff --git a/VERSION b/VERSION index e12cd6b..a4efc32 100644 --- a/VERSION +++ b/VERSION
@@ -1 +1 @@ -11.0.50 +11.0.90
diff --git a/contrib/gitdm/group-map-ibm b/contrib/gitdm/group-map-ibm deleted file mode 100644 index 24d8dc1..0000000 --- a/contrib/gitdm/group-map-ibm +++ /dev/null
@@ -1,15 +0,0 @@ -# -# Some IBM contributors submit via another domain -# - -aik@ozlabs.ru -andrew@aj.id.au -benh@kernel.crashing.org -clg@kaod.org -danielhb413@gmail.com -groug@kaod.org -jcfaracco@gmail.com -joel@jms.id.au -sjitindarsingh@gmail.com -tommusta@gmail.com -idan.horowitz@gmail.com
diff --git a/contrib/plugins/dlcall.c b/contrib/plugins/dlcall.c new file mode 100644 index 0000000..9d2230b --- /dev/null +++ b/contrib/plugins/dlcall.c
@@ -0,0 +1,248 @@ +/* + * Copyright (C) 2026, Ziyang Zhang <functioner@sjtu.edu.cn> + * + * dlcall (Dynamic Linking Call) plugin: lets a linux-user guest invoke host + * functions by issuing a magic system call. The guest can ask QEMU to dlopen() + * a host shared library, dlsym() a symbol, and call it with guest-supplied + * arguments. + * + * The plugin intentionally keeps the QEMU side lightweight and prescribes + * nothing about how a library is thunked. Any toolchain can implement the + * userspace side. Lorelei is one end-to-end implementation (guest/host + * runtimes plus a thunk compiler that generates thunks from a library's + * headers): + * https://github.com/rover2024/lorelei + * + * See docs/about/emulation.rst|Dynamic Linking Call for details and examples. + * + * WARNING: trusted guests only. The guest can load arbitrary host libraries + * and execute arbitrary host code with arbitrary arguments, i.e. full code + * execution in the QEMU host process. It is NOT a sandbox and provides no + * isolation; only load it for guests you fully trust. + * + * WARNING: requires guest_base == 0, which is qemu-user's default. Pointer + * operands are dereferenced as host addresses directly, and the invoked host + * functions dereference guest pointers with no address translation, so guest + * and host must share a single address space. A non-zero guest_base (e.g. set + * via -B/-R) would make every pointer off by guest_base and hit unrelated + * host memory. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <glib.h> +#include <dlfcn.h> + +#include <qemu-plugin.h> + +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + +/* + * The magic system call number for dlcall. + * + * It defaults to DLCALL_SYSCALL_DEFAULT and can be overridden at load time + * with the "syscall_num=N" argument. To avoid hijacking a real syscall the + * guest might issue, N must be at least DLCALL_SYSCALL_MIN: every Linux ABI + * keeps its syscall numbers well below this; numbers from here up are free. + */ +enum { + DLCALL_SYSCALL_DEFAULT = 4096, + DLCALL_SYSCALL_MIN = 4096, +}; + +static int64_t dlcall_syscall_num = DLCALL_SYSCALL_DEFAULT; + +/* + * dlcall calling convention. + * + * The guest issues the magic system call (dlcall_syscall_num). The first + * argument (a1) is one of the call IDs below; the remaining arguments (a2, a3, + * a4, ...) are that ID's operands. All pointer operands are guest virtual + * addresses that the plugin dereferences as host addresses directly (see the + * guest_base requirement above). Results are written back through + * caller-provided "out" pointers rather than returned in the syscall value. + * + * The syscall return value (*sysret) only reports dispatch status: 0 on a + * recognised ID, -EINVAL for an unknown one. The actual success/failure of an + * operation (e.g. a NULL handle from dlopen) is delivered through its out + * pointer, exactly like the underlying libdl call. + * + * Operands per ID: + * + * DLCALL_ID_GET_HOST_ATTRIBUTE + * a2 const char *key in: attribute name to query + * a3 const char **attr_ptr out: matching value, or NULL if unknown + * + * DLCALL_ID_LOAD_LIBRARY (wraps dlopen) + * a2 const char *path in: library path + * a3 int flags in: dlopen() flags (e.g. RTLD_NOW) + * a4 void **handle_ptr out: library handle, or NULL on failure + * + * DLCALL_ID_GET_PROC_ADDRESS (wraps dlsym) + * a2 void *handle in: library handle + * a3 const char *name in: symbol name + * a4 void **entry_ptr out: symbol address, or NULL if not found + * + * DLCALL_ID_FREE_LIBRARY (wraps dlclose) + * a2 void *handle in: library handle + * a3 int *ret_ptr out: dlclose() return value (0 on success) + * + * DLCALL_ID_GET_LIBRARY_ERROR (wraps dlerror) + * a2 const char **error_ptr out: last libdl error string, or NULL + * + * DLCALL_ID_INVOKE_PROC (calls the symbol) + * a2 void *proc in: function pointer, signature + * void (*)(void *arg1, void *arg2) + * a3 void *arg1 in: first argument forwarded to proc + * a4 void *arg2 in: second argument forwarded to proc + */ +enum DlcallID { + DLCALL_ID_GET_HOST_ATTRIBUTE, + DLCALL_ID_LOAD_LIBRARY, + DLCALL_ID_GET_PROC_ADDRESS, + DLCALL_ID_FREE_LIBRARY, + DLCALL_ID_GET_LIBRARY_ERROR, + DLCALL_ID_INVOKE_PROC, +}; + +static inline const char *query_host_attribute(const char *key) +{ + if (strcmp(key, "emu") == 0) { + return "qemu"; + } + return NULL; +} + +static inline void invoke_proc(void *proc, void *arg1, void *arg2) +{ + typedef void (*Func)(void * /*arg1*/, void * /*arg2*/); + Func func = (Func) proc; + func(arg1, arg2); +} + +static bool vcpu_syscall_filter(unsigned int vcpu_index, + int64_t num, uint64_t a1, uint64_t a2, + uint64_t a3, uint64_t a4, uint64_t a5, + uint64_t a6, uint64_t a7, uint64_t a8, + int64_t *sysret, void *userdata) +{ + if (num == dlcall_syscall_num) { + switch (a1) { + /* Query host attribute by a reserved key. */ + case DLCALL_ID_GET_HOST_ATTRIBUTE: { + const char *key = (const char *) a2; + const char **attr_ptr = (const char **) a3; + assert(attr_ptr); + *attr_ptr = query_host_attribute(key); + *sysret = 0; + break; + } + + /* Load a shared library. */ + case DLCALL_ID_LOAD_LIBRARY: { + const char *path = (const char *) a2; + int flags = (int) a3; + void **handle_ptr = (void **) a4; + assert(handle_ptr); + *handle_ptr = dlopen(path, flags); + *sysret = 0; + break; + } + + /* Get the address of a function in a shared library. */ + case DLCALL_ID_GET_PROC_ADDRESS: { + void *handle = (void *) a2; + const char *name = (const char *) a3; + void **entry_ptr = (void **) a4; + assert(entry_ptr); + *entry_ptr = dlsym(handle, name); + *sysret = 0; + break; + } + + /* Free a shared library. */ + case DLCALL_ID_FREE_LIBRARY: { + void *handle = (void *) a2; + int *ret_ptr = (int *) a3; + *ret_ptr = dlclose(handle); + *sysret = 0; + break; + } + + /* Get the last error message for a library event. */ + case DLCALL_ID_GET_LIBRARY_ERROR: { + const char **error_ptr = (const char **) a2; + *error_ptr = dlerror(); + *sysret = 0; + break; + } + + /* Invoke a function of a common interface. */ + case DLCALL_ID_INVOKE_PROC: { + void *proc = (void *) a2; + void *arg1 = (void *) a3; + void *arg2 = (void *) a4; + assert(proc); + invoke_proc(proc, arg1, arg2); + *sysret = 0; + break; + } + + default: + *sysret = -EINVAL; + break; + } + return true; + } + return false; +} + +QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, + const qemu_info_t *info, + int argc, char **argv) +{ + if (info->system_emulation) { + fprintf(stderr, "plugin dlcall: only useful for user emulation\n"); + return -1; + } + + for (int i = 0; i < argc; i++) { + char *opt = argv[i]; + g_auto(GStrv) tokens = g_strsplit(opt, "=", 2); + if (g_strcmp0(tokens[0], "syscall_num") == 0) { + const char *val = tokens[1]; + char *endptr = NULL; + guint64 num; + if (!val || *val == '\0') { + fprintf(stderr, + "plugin dlcall: missing value for syscall_num\n"); + return -1; + } + num = g_ascii_strtoull(val, &endptr, 0); + if (*endptr != '\0' || g_strrstr(val, "-") != NULL) { + fprintf(stderr, + "plugin dlcall: invalid syscall_num '%s'\n", val); + return -1; + } + if (num < DLCALL_SYSCALL_MIN || num > G_MAXINT64) { + fprintf(stderr, + "plugin dlcall: syscall_num %s is out of range; " + "it must be >= %d to avoid clashing with a real " + "syscall\n", val, DLCALL_SYSCALL_MIN); + return -1; + } + dlcall_syscall_num = (int64_t) num; + } else { + fprintf(stderr, "plugin dlcall: unknown option '%s'\n", opt); + return -1; + } + } + + qemu_plugin_register_vcpu_syscall_filter_cb(id, vcpu_syscall_filter, NULL); + + return 0; +}
diff --git a/contrib/plugins/meson.build b/contrib/plugins/meson.build index 099319e..e7fc4d6 100644 --- a/contrib/plugins/meson.build +++ b/contrib/plugins/meson.build
@@ -19,6 +19,11 @@ contrib_plugins += 'lockstep.c' endif +if host_os == 'linux' + # dlcall passes guest calls through to host libraries; linux-user only + contrib_plugins += 'dlcall.c' +endif + if 'cpp' in all_languages contrib_plugins += 'cpp.cpp' endif
diff --git a/contrib/plugins/uftrace.c b/contrib/plugins/uftrace.c index 9b0a496..063e322 100644 --- a/contrib/plugins/uftrace.c +++ b/contrib/plugins/uftrace.c
@@ -109,6 +109,8 @@ RISCV64_SUPERVISOR, RISCV64_RESERVED, RISCV64_MACHINE, + RISCV64_VUSER, + RISCV64_VSUPERVISOR, RISCV64_PRIVILEGE_LEVEL_MAX, } Riscv64PrivilegeLevel; @@ -153,8 +155,10 @@ const char *path = "./uftrace.data/sid-0.map"; if (system_emulation && access(path, F_OK) == 0) { - /* do not erase existing map in system emulation, as a custom one might - * already have been generated by uftrace_symbols.py */ + /* + * do not erase existing map in system emulation, as a custom one might + * already have been generated by uftrace_symbols.py + */ return; } @@ -706,6 +710,8 @@ case RISCV64_SUPERVISOR: return "Supervisor"; case RISCV64_RESERVED: return "Unknown"; case RISCV64_MACHINE: return "Machine"; + case RISCV64_VUSER: return "VUser"; + case RISCV64_VSUPERVISOR: return "VSupervisor"; default: g_assert_not_reached(); } @@ -986,7 +992,8 @@ score = qemu_plugin_scoreboard_new(sizeof(Cpu)); qemu_plugin_register_vcpu_init_cb(id, vcpu_init, NULL); - qemu_plugin_register_atexit_cb(id, at_exit, (void *) info->system_emulation); + qemu_plugin_register_atexit_cb(id, at_exit, + (void *) info->system_emulation); qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans, NULL); return 0;
diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst index 3b4c365..b861501 100644 --- a/docs/about/emulation.rst +++ b/docs/about/emulation.rst
@@ -1046,6 +1046,164 @@ This plugin counts the number of interrupts (asynchronous events), exceptions (synchronous events) and host calls (e.g. semihosting) per cpu. +Dynamic Linking Call +.................... + +``contrib/plugins/dlcall.c`` + +This plugin provides a dynamic linking function call interception mechanism +for linux-user guests: the guest hands a call off to the host, where the plugin +runs native code in its place instead of the guest emulating it. Interception +alone enables several uses, for instance tracing or auditing guest calls. +One use is acceleration by leveraging the host's native shared libraries. For +example, a thunk layer can run the stock zlib ``minizip`` utility under +emulation while forwarding its ``deflate`` calls to the host's native zlib +library (libz). This avoids emulating those selected library calls instruction +by instruction. + +The guest issues a reserved "magic" system call (4096 by default, configurable +with ``syscall_num=N``) whose first argument selects a pass-through operation: +dlopen/dlclose a host library, dlsym a symbol, and invoke a resolved host +function. The plugin performs the operation on the host and consumes the +syscall, so the real kernel never sees it. + +.. warning:: + + Trusted guests only. The guest can load arbitrary host libraries and run + arbitrary code in the QEMU host process. The plugin is not a sandbox and + provides no isolation. It also requires ``guest_base == 0`` (qemu-user's + default), as guest pointers are dereferenced as host addresses with no + translation. + +The plugin intentionally keeps the QEMU side lightweight and knows nothing +about any particular library or its calling convention. Turning a real library +into working thunks, including argument marshalling, callbacks and variadic +functions, is done entirely in userspace, and any toolchain can implement the +interface. + +Loading the plugin is all that is required from QEMU's side: + +.. code-block:: shell + + qemu-x86_64 -plugin contrib/plugins/libdlcall.so <guest-program> ... + +`Lorelei <https://github.com/rover2024/lorelei>`_ is one end-to-end userspace +implementation of this: it provides the guest and host runtimes and an +automated toolchain that generates the thunks from a library's headers, so guest +library calls run on the host's native libraries. It supports an x86_64 guest +running on an x86_64, aarch64 or riscv64 host. + +A minimal end-to-end example uses a one-function library, ``libhello.so``, built +two ways: the guest build tags its output ``(from the guest)`` and the host +build ``(from the host)``. An unmodified guest program ``main`` calls +``hello("World", 7)``, and the thunk makes that same binary reach the host build +in place of its own. The sources live under ``src/``: + +.. code-block:: c + + /* src/hello.h */ + void hello(const char *name, int lucky); + +.. code-block:: c + + /* src/hello_guest.c */ + #include "hello.h" + #include <stdio.h> + + void hello(const char *name, int lucky) + { + printf("Hello, %s! Your lucky number is %d. (from the guest)\n", name, lucky); + } + +.. code-block:: c + + /* src/hello_host.c */ + #include "hello.h" + #include <stdio.h> + + void hello(const char *name, int lucky) + { + printf("Hello, %s! Your lucky number is %d. (from the host)\n", name, lucky); + } + +.. code-block:: c + + /* src/main.c */ + #include "hello.h" + + int main(void) + { + hello("World", 7); + return 0; + } + +Lorelei ships a prebuilt toolchain (a "devkit") in its releases. Download the +one for your host and unpack it: + +.. code-block:: shell + + # ARCH is your host's architecture: x86_64, aarch64 or riscv64. This example uses aarch64. + # See https://github.com/rover2024/lorelei/releases + ARCH=aarch64 + VERSION=$(curl -fsSL -o /dev/null -w '%{url_effective}' \ + https://github.com/rover2024/lorelei/releases/latest | sed 's|.*/tag/v||') + wget "https://github.com/rover2024/lorelei/releases/download/v$VERSION/lorelei-devkit-$ARCH-$VERSION.tar.xz" + tar -xf lorelei-devkit-$ARCH-$VERSION.tar.xz + DEVKIT=lorelei-devkit-$ARCH + +Build the guest ``libhello.so`` (x86_64) and the host ``libhello.so`` (this +host's architecture), then the guest program: + +.. code-block:: shell + + mkdir -p build/guest build/host + $DEVKIT/bin/x86_64-linux-gnu-clang -shared -fPIC src/hello_guest.c -o build/guest/libhello.so + cc -shared -fPIC src/hello_host.c -o build/host/libhello.so + $DEVKIT/bin/x86_64-linux-gnu-clang src/main.c -Isrc -Lbuild/guest -lhello -o build/guest/main + +Run it under qemu: + +.. code-block:: shell + + qemu-x86_64 -L /usr/x86_64-linux-gnu/ -E LD_LIBRARY_PATH=build/guest build/guest/main + +which prints:: + + Hello, World! Your lucky number is 7. (from the guest) + +Now generate the thunk from the host ``libhello.so``. This produces a guest-side +``libhello.so`` that stands in for the guest build, and a host-side thunk library +that dispatches to the host build: + +.. code-block:: shell + + $DEVKIT/bin/LoreMakeThunk.py --name hello --lib build/host/libhello.so \ + --header hello.h -o thunks -- -Isrc + +Run the same ``main`` under the plugin. The call reaches the host build now: + +.. code-block:: shell + + LD_LIBRARY_PATH=$DEVKIT/lib:build/host \ + qemu-x86_64 -plugin contrib/plugins/libdlcall.so \ + -E LD_LIBRARY_PATH=$DEVKIT/x86_64/lib:thunks/x86_64 \ + -L /usr/x86_64-linux-gnu/ \ + build/guest/main + +which prints:: + + Hello, World! Your lucky number is 7. (from the host) + +.. list-table:: Dynamic Linking Call arguments + :widths: 20 80 + :header-rows: 1 + + * - Option + - Description + * - syscall_num=N + - The magic syscall number the guest issues (default 4096). Must be high + enough not to clash with a real syscall. + Other emulation features ------------------------
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 4f413d6..9930974 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst
@@ -31,6 +31,8 @@ - FEAT_BBML1 (Translation table break-before-make level 1) - FEAT_BBML2 (Translation table break-before-make level 2) - FEAT_BF16 (AArch64 BFloat16 instructions) +- FEAT_BigEnd (Support for big-endian at EL1 and above) +- FEAT_BigEndEL0 (Support for big-endian at EL0) - FEAT_BTI (Branch Target Identification) - FEAT_CCIDX (Extended cache index) - FEAT_CHK (Check Feature Status) @@ -68,6 +70,7 @@ - FEAT_EPAC (Enhanced pointer authentication) - FEAT_ETS2 (Enhanced Translation Synchronization) - FEAT_EVT (Enhanced Virtualization Traps) +- FEAT_EVT2 (Enhanced Virtualization Traps 2) - FEAT_F8F16MM (8-bit floating-point matrix multiply-accumulate to half-precision) - FEAT_F8F32MM (8-bit floating-point matrix multiply-accumulate to single-precision) - FEAT_F32MM (Single-precision Matrix Multiplication) @@ -92,6 +95,7 @@ - FEAT_FlagM2 (Enhancements to flag manipulation instructions) - FEAT_GCS (Guarded Control Stack Extension) - FEAT_GTG (Guest translation granule size) +- FEAT_HAF (Hardware management of the Access flag) - FEAT_HAFDBS (Hardware management of the access flag and dirty bit state) - FEAT_HBC (Hinted conditional branches) - FEAT_HCX (Support for the HCRX_EL2 register) @@ -101,7 +105,10 @@ - FEAT_I8MM (AArch64 Int8 matrix multiplication instructions) - FEAT_IDST (ID space trap handling) - FEAT_IESB (Implicit error synchronization event) +- FEAT_IVIPT (The IVIPT Extension) - FEAT_JSCVT (JavaScript conversion instructions) +- FEAT_LittleEnd (Support for little-endian at EL1 and above) +- FEAT_LittleEndEL0 (Support for little-endian at EL0) - FEAT_LOR (Limited ordering regions) - FEAT_LPA (Large Physical Address space) - FEAT_LPA2 (Large Physical and virtual Address space v2) @@ -121,6 +128,7 @@ - FEAT_MTE (Memory Tagging Extension) - FEAT_MTE2 (Memory Tagging Extension) - FEAT_MTE3 (MTE Asymmetric Fault Handling) +- FEAT_MTE4 (Enhanced Memory Tagging Extension) - FEAT_MTE_ASYM_FAULT (Memory tagging asymmetric faults) - FEAT_MTE_ASYNC (Asynchronous reporting of Tag Check Fault) - FEAT_MTE_CANONICAL_TAGS (Canonical tag checking) @@ -153,10 +161,14 @@ - FEAT_RNG_TRAP (Trapping support for RNDR/RNDRRS) - FEAT_RPRES (Increased precision of FRECPE and FRSQRTE) - FEAT_S1PIE (Stage 1 permission indirections) -- FEAT_S2PIE (Stage 2 permission indirections) - FEAT_S2FWB (Stage 2 forced Write-Back) +- FEAT_S2PIE (Stage 2 permission indirections) +- FEAT_S2TGran16K (Support for 16KB memory translation granule size at stage 2) +- FEAT_S2TGran4K (Support for 4KB memory translation granule size at stage 2) +- FEAT_S2TGran64K (Support for 64KB memory translation granule size at stage 2) - FEAT_SB (Speculation Barrier) - FEAT_SCTLR2 (Extension to SCTLR_ELx) +- FEAT_Secure (Support for Secure state) - FEAT_SEL2 (Secure EL2) - FEAT_SHA1 (SHA1 instructions) - FEAT_SHA256 (SHA256 instructions)
diff --git a/gitdm.config b/gitdm.config index 8764bf2..b9627de 100644 --- a/gitdm.config +++ b/gitdm.config
@@ -17,13 +17,13 @@ # the information in the existing .mailmap but in a slightly different # form. # -EmailAliases contrib/gitdm/aliases +EmailAliases scripts/gitdm/aliases # # EmailMap does the main work of mapping addresses onto # employers. # -EmailMap contrib/gitdm/domain-map +EmailMap scripts/gitdm/domain-map # # Use GroupMap to map a file full of addresses to the @@ -31,31 +31,31 @@ # identifiable corporate emails. Please keep this list sorted. # -GroupMap contrib/gitdm/group-map-alibaba Alibaba -GroupMap contrib/gitdm/group-map-amd AMD -GroupMap contrib/gitdm/group-map-cadence Cadence Design Systems -GroupMap contrib/gitdm/group-map-codeweavers CodeWeavers -GroupMap contrib/gitdm/group-map-facebook Facebook -GroupMap contrib/gitdm/group-map-huawei Huawei -GroupMap contrib/gitdm/group-map-ibm IBM -GroupMap contrib/gitdm/group-map-janustech Janus Technologies -GroupMap contrib/gitdm/group-map-microsoft Microsoft -GroupMap contrib/gitdm/group-map-netflix Netflix -GroupMap contrib/gitdm/group-map-redhat Red Hat -GroupMap contrib/gitdm/group-map-wavecomp Wave Computing +GroupMap scripts/gitdm/group-map-alibaba Alibaba +GroupMap scripts/gitdm/group-map-amd AMD +GroupMap scripts/gitdm/group-map-cadence Cadence Design Systems +GroupMap scripts/gitdm/group-map-codeweavers CodeWeavers +GroupMap scripts/gitdm/group-map-facebook Facebook +GroupMap scripts/gitdm/group-map-huawei Huawei +GroupMap scripts/gitdm/group-map-ibm IBM +GroupMap scripts/gitdm/group-map-janustech Janus Technologies +GroupMap scripts/gitdm/group-map-microsoft Microsoft +GroupMap scripts/gitdm/group-map-netflix Netflix +GroupMap scripts/gitdm/group-map-redhat Red Hat +GroupMap scripts/gitdm/group-map-wavecomp Wave Computing # Also group together our prolific individual contributors # and those working under academic or intern auspices -GroupMap contrib/gitdm/group-map-individuals (None) -GroupMap contrib/gitdm/group-map-academics Academics (various) -GroupMap contrib/gitdm/group-map-interns GSoC/Outreachy Interns +GroupMap scripts/gitdm/group-map-individuals (None) +GroupMap scripts/gitdm/group-map-academics Academics (various) +GroupMap scripts/gitdm/group-map-interns GSoC/Outreachy Interns # Group together robots and other auto-reporters -GroupMap contrib/gitdm/group-map-robots Robots (various) +GroupMap scripts/gitdm/group-map-robots Robots (various) # # # Use FileTypeMap to map a file types to file names using regular # regular expressions. # -FileTypeMap contrib/gitdm/filetypes.txt +FileTypeMap scripts/gitdm/filetypes.txt
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index eb482c7..0819a4b 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h
@@ -359,6 +359,9 @@ void smmuv3_propagate_event(SMMUv3State *s, Evt *evt); int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event); +#define STE_SIZE 6 +#define L1STD_SIZE 3 + static inline int oas2bits(int oas_field) { switch (oas_field) {
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 5e5a6a9..ed19536 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c
@@ -664,7 +664,7 @@ { dma_addr_t addr, strtab_base; uint32_t log2size; - int strtab_size_shift; + int strtab_size; int ret; trace_smmuv3_find_ste(sid, s->features, s->sid_split); @@ -685,9 +685,9 @@ * Align strtab base address to table size. For this purpose, assume it * is not bounded by SMMU_IDR1_SIDSIZE. */ - strtab_size_shift = MAX(5, (int)log2size - s->sid_split - 1 + 3); + strtab_size = MAX(6, (int)log2size - s->sid_split + L1STD_SIZE); strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK & - ~MAKE_64BIT_MASK(0, strtab_size_shift); + ~MAKE_64BIT_MASK(0, strtab_size); l1_ste_offset = sid >> s->sid_split; l2_ste_offset = sid & ((1 << s->sid_split) - 1); l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset * sizeof(l1std)); @@ -707,7 +707,7 @@ span = L1STD_SPAN(&l1std); - if (!span) { + if (!span || span > 11) { /* l2ptr is not valid */ if (!event->inval_ste_allowed) { qemu_log_mask(LOG_GUEST_ERROR, @@ -716,8 +716,20 @@ event->type = SMMU_EVT_C_BAD_STREAMID; return -EINVAL; } + + if (span > s->sid_split + 1) { + if (!event->inval_ste_allowed) { + qemu_log_mask(LOG_GUEST_ERROR, + "invalid span (0x%x)\n", span); + } + event->type = SMMU_EVT_C_BAD_STREAMID; + return -EINVAL; + } + max_l2_ste = (1 << span) - 1; l2ptr = l1std_l2ptr(&l1std); + + l2ptr &= ~MAKE_64BIT_MASK(0, 6 + (span - 1)); trace_smmuv3_find_ste_2lvl(s->strtab_base, l1ptr, l1_ste_offset, l2ptr, l2_ste_offset, max_l2_ste); if (l2_ste_offset > max_l2_ste) { @@ -729,9 +741,10 @@ } addr = l2ptr + l2_ste_offset * sizeof(*ste); } else { - strtab_size_shift = log2size + 5; + strtab_size = log2size + STE_SIZE; + strtab_size = MIN(64, strtab_size); strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK & - ~MAKE_64BIT_MASK(0, strtab_size_shift); + ~MAKE_64BIT_MASK(0, strtab_size); addr = strtab_base + sid * sizeof(*ste); } @@ -1688,6 +1701,13 @@ s->strtab_base_cfg = data; if (FIELD_EX32(data, STRTAB_BASE_CFG, FMT) == 1) { s->sid_split = FIELD_EX32(data, STRTAB_BASE_CFG, SPLIT); + if (s->sid_split != 6 && s->sid_split != 8 && s->sid_split != 10) { + /* Other values are reserved, behave as 6 */ + qemu_log_mask(LOG_GUEST_ERROR, + "Invalid STRTAB_BASE_CFG.SPLIT=%u, use 6 instead\n", + s->sid_split); + s->sid_split = 6; + } s->features |= SMMU_FEATURE_2LVL_STE; } break;
diff --git a/hw/arm/tegra241-cmdqv.c b/hw/arm/tegra241-cmdqv.c index 7223aa9..273633e 100644 --- a/hw/arm/tegra241-cmdqv.c +++ b/hw/arm/tegra241-cmdqv.c
@@ -212,7 +212,9 @@ /* * Flush cached register writes into the mmap'd host VINTF page0 after a * successful HW_QUEUE_ALLOC, so the guest's earlier writes survive - * the cache-to-hardware transition. + * the cache-to-hardware transition. GERRORN is intentionally not synced, + * as overwriting it with the cached value could recreate a GERROR != GERRORN + * mismatch and stall the VCMDQ. */ static void tegra241_cmdqv_sync_vcmdq(Tegra241CMDQV *cmdqv, int index) { @@ -229,9 +231,6 @@ ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, A_VCMDQ0_CONFIG); *ptr = cmdqv->vcmdq_config[index]; - - ptr = tegra241_cmdqv_vintf_lvcmdq_ptr(cmdqv, index, A_VCMDQ0_GERRORN); - *ptr = cmdqv->vcmdq_gerrorn[index]; } /*
diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 6a3c69b..219597c 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c
@@ -4417,6 +4417,7 @@ } g_free(vms->oem_id); g_free(vms->oem_table_id); + g_ptr_array_free(vms->smmuv3_devices, TRUE); } static const TypeInfo virt_machine_info = {
diff --git a/hw/display/sm501.c b/hw/display/sm501.c index af87004..cacb6c8 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c
@@ -571,6 +571,25 @@ return index; } +static void set_new_local_mem_size_index(SM501State *s, uint32_t idx) +{ + /* + * Update local_mem_size_index on guest write. We don't allow this + * to be set to larger than the actual RAM size. (The guest will + * still read back the SYSTEM_CONTROL.Size bits that it wrote.) + */ + if (idx < ARRAY_SIZE(sm501_mem_local_size) && + sm501_mem_local_size[idx] <= memory_region_size(&s->local_mem_region)) { + s->local_mem_size_index = idx; + return; + } + qemu_log_mask(LOG_GUEST_ERROR, + "sm501: Guest set DRAM_CONTROL.Size to 0x%x but " + "local memory is not that large\n", + idx); + /* Don't change the effective size, leave it as whatever it was */ +} + static ram_addr_t get_fb_addr(SM501State *s, int crt) { return (crt ? s->dc_crt_fb_addr : s->dc_panel_fb_addr) & 0x3FFFFF0; @@ -682,6 +701,28 @@ get_fb_addr(s, crt) + start, end - start); } +static bool sm501_rect_outside_vram(SM501State *s, uint32_t base, + uint32_t x, uint32_t y, + uint32_t width, uint32_t height, + uint32_t pitch, uint32_t bypp) +{ + /* + * Return true if the 2D area specified by the arguments is + * partially or completely outside the VRAM (a guest error) + * + * Limits on the input sizes mean we can't overflow as long as + * we do all the arithmetic at 64 bits. + */ + uint64_t rect_size, last_addr; + + assert(x <= UINT16_MAX && y <= UINT16_MAX && height <= UINT16_MAX && + pitch <= UINT16_MAX && bypp <= 8); + rect_size = (((uint64_t)y + height) * pitch + x + width) * bypp; + last_addr = base + rect_size; + + return last_addr >= get_local_mem_size(s); +} + static void sm501_2d_operation(SM501State *s) { int cmd = (s->twoD_control >> 16) & 0x1F; @@ -723,13 +764,16 @@ } if (rtl) { + if (dst_x < (width - 1) || dst_y < (height - 1)) { + qemu_log_mask(LOG_GUEST_ERROR, "sm501: RTL op out of bounds\n"); + return; + } dst_x -= width - 1; dst_y -= height - 1; } - if (dst_base >= get_local_mem_size(s) || - dst_base + (dst_x + width + (dst_y + height) * dst_pitch) * bypp >= - get_local_mem_size(s)) { + if (sm501_rect_outside_vram(s, dst_base, dst_x, dst_y, width, height, + dst_pitch, bypp)) { qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n"); return; } @@ -748,13 +792,16 @@ } if (rtl) { + if (src_x < (width - 1) || src_y < (height - 1)) { + qemu_log_mask(LOG_GUEST_ERROR, "sm501: RTL op out of bounds\n"); + return; + } src_x -= width - 1; src_y -= height - 1; } - if (src_base >= get_local_mem_size(s) || - src_base + (src_x + width + (src_y + height) * src_pitch) * bypp >= - get_local_mem_size(s)) { + if (sm501_rect_outside_vram(s, src_base, src_x, src_y, width, height, + src_pitch, bypp)) { qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op src is outside vram.\n"); return; @@ -962,7 +1009,7 @@ ret = 0x050100A0; break; case SM501_DRAM_CONTROL: - ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13; + ret = (s->dram_control & 0x07F1E7C0); break; case SM501_ARBTRTN_CONTROL: ret = s->arbitration_control; @@ -1021,8 +1068,7 @@ s->gpio_63_32_control = value & 0xFF80FFFF; break; case SM501_DRAM_CONTROL: - s->local_mem_size_index = (value >> 13) & 0x7; - /* TODO : check validity of size change */ + set_new_local_mem_size_index(s, (value >> 13) & 0x7); s->dram_control &= 0x80000000; s->dram_control |= value & 0x7FFFFFC3; break;
diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c index d07459d..b842aef 100644 --- a/hw/dma/bcm2835_dma.c +++ b/hw/dma/bcm2835_dma.c
@@ -86,6 +86,23 @@ } xlen_td = xlen; + if (ch->ti & BCM2708_DMA_D_WIDTH) { + qemu_log_mask(LOG_UNIMP, "%s: 128bit transfers not yet supported", __func__); + ch->cs |= BCM2708_DMA_ERR; + break; + } + + /* + * Datasheet implies 32bit or 128bit transfers only + * + * TODO: test on real HW and report back. + */ + if (xlen & 0x3) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad transfer size\n", __func__); + ch->cs |= BCM2708_DMA_ERR; + break; + } + while (ylen != 0) { /* Normal transfer mode */ while (xlen != 0) {
diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c index b1f9843..1ca117bd 100644 --- a/hw/i2c/pmbus_device.c +++ b/hw/i2c/pmbus_device.c
@@ -1245,6 +1245,16 @@ pmdev->in_buf_len = len; pmdev->in_buf = buf; + /* clear the output buffer on any new write transaction */ + if (pmdev->out_buf_len != 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: previous read was not completed, %d bytes dropped\n", + __func__, pmdev->out_buf_len); + + pmdev->out_buf_len = 0; + memset(pmdev->out_buf, 0, sizeof(pmdev->out_buf)); + } + pmdev->code = buf[0]; /* PMBus command code */ if (pmdev->code == PMBUS_CLEAR_FAULTS) {
diff --git a/hw/misc/allwinner-r40-ccu.c b/hw/misc/allwinner-r40-ccu.c index 8ba4e7a..00840e9 100644 --- a/hw/misc/allwinner-r40-ccu.c +++ b/hw/misc/allwinner-r40-ccu.c
@@ -71,7 +71,7 @@ const uint32_t idx = REG_INDEX(offset); switch (offset) { - case 0x324 ... AW_R40_CCU_IOSIZE: + case 0x324 ... AW_R40_CCU_IOSIZE - 4: qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", __func__, (uint32_t)offset); return 0; @@ -113,10 +113,10 @@ val |= REG_PLL_LOCK; } break; - case 0x324 ... AW_R40_CCU_IOSIZE: + case 0x324 ... AW_R40_CCU_IOSIZE - 4: qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", __func__, (uint32_t)offset); - break; + return; default: qemu_log_mask(LOG_UNIMP, "%s: unimplemented write offset 0x%04x\n", __func__, (uint32_t)offset);
diff --git a/hw/misc/stm32_rcc.c b/hw/misc/stm32_rcc.c index 74ea29b..5cfb39e 100644 --- a/hw/misc/stm32_rcc.c +++ b/hw/misc/stm32_rcc.c
@@ -53,6 +53,27 @@ return value; } +static int reg_offset_to_irq_offset(hwaddr addr) +{ + /* + * The reset and enable registers aren't all consecutive. In getting the + * irq index from the register offset, we need to account for the gap + * between the AHB regs and the APB regs. + */ + switch (addr) { + case STM32_RCC_AHB1_RSTR ... STM32_RCC_AHB3_RSTR: + return ((addr - STM32_RCC_AHB1_RSTR) / 4) * 32; + case STM32_RCC_APB1_RSTR ... STM32_RCC_APB2_RSTR: + return ((addr - STM32_RCC_APB1_RSTR) / 4) * 32 + STM32_RCC_N_AHB_IRQS; + case STM32_RCC_AHB1_ENR ... STM32_RCC_AHB3_ENR: + return ((addr - STM32_RCC_AHB1_ENR) / 4) * 32; + case STM32_RCC_APB1_ENR ... STM32_RCC_APB2_ENR: + return ((addr - STM32_RCC_APB1_ENR) / 4) * 32 + STM32_RCC_N_AHB_IRQS; + default: + g_assert_not_reached(); + } +} + static void stm32_rcc_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { @@ -69,11 +90,12 @@ } switch (addr) { - case STM32_RCC_AHB1_RSTR...STM32_RCC_APB2_RSTR: + case STM32_RCC_AHB1_RSTR ... STM32_RCC_AHB3_RSTR: + case STM32_RCC_APB1_RSTR ... STM32_RCC_APB2_RSTR: prev_value = s->regs[addr / 4]; s->regs[addr / 4] = value; - irq_offset = ((addr - STM32_RCC_AHB1_RSTR) / 4) * 32; + irq_offset = reg_offset_to_irq_offset(addr); for (int i = 0; i < 32; i++) { new_value = extract32(value, i, 1); if (extract32(prev_value, i, 1) && !new_value) { @@ -82,11 +104,12 @@ } } return; - case STM32_RCC_AHB1_ENR...STM32_RCC_APB2_ENR: + case STM32_RCC_AHB1_ENR ... STM32_RCC_AHB3_ENR: + case STM32_RCC_APB1_ENR ... STM32_RCC_APB2_ENR: prev_value = s->regs[addr / 4]; s->regs[addr / 4] = value; - irq_offset = ((addr - STM32_RCC_AHB1_ENR) / 4) * 32; + irq_offset = reg_offset_to_irq_offset(addr); for (int i = 0; i < 32; i++) { new_value = extract32(value, i, 1); if (!extract32(prev_value, i, 1) && new_value) {
diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index 0ae5d60..d0f899c 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c
@@ -427,7 +427,6 @@ = s->regs[R_DDRIOB + 3] = 0x00000e00; s->regs[R_DDRIOB + 4] = s->regs[R_DDRIOB + 5] = s->regs[R_DDRIOB + 6] = 0x00000e00; - s->regs[R_DDRIOB + 12] = 0x00000021; s->regs[R_DDRIOB_DCI_CTRL] = 0x00000020; }
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 97156dd..8569484 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c
@@ -1079,7 +1079,7 @@ int tx_queue_idx = VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_TXPROD, VMXNET3_REG_ALIGN); - if (tx_queue_idx <= s->txq_num) { + if (tx_queue_idx < s->txq_num) { vmxnet3_process_tx_queue(s, tx_queue_idx); } else { qemu_log_mask(LOG_GUEST_ERROR, "vmxnet3: Illegal TX queue %d/%d\n",
diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 29ba39f..3a67b67 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c
@@ -1078,6 +1078,12 @@ ret = -EINVAL; break; } + /* Limit the number of TICs in a given channel program */ + if (sch->ccw_tic_cnt == 255) { + ret = -EINVAL; + break; + } + sch->ccw_tic_cnt++; sch->channel_prog = ccw.cda; ret = -EAGAIN; break; @@ -1129,6 +1135,7 @@ sch->ccw_fmt_1 = !!(orb->ctrl0 & ORB_CTRL0_MASK_FMT); schib->scsw.flags |= (sch->ccw_fmt_1) ? SCSW_FLAGS_MASK_FMT : 0; sch->ccw_no_data_cnt = 0; + sch->ccw_tic_cnt = 0; suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND); } else { /* Start Function resumed via rsch */
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 2d2cde7..3c8cb16 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c
@@ -329,7 +329,8 @@ /* * we want to work on a private copy of the sccb, to prevent guests * from playing dirty tricks by modifying the memory content after - * the host has checked the values + * the host has checked the values. + * Reuse the previously fetched header */ work_sccb = g_malloc0(be16_to_cpu(header.length)); ret = address_space_read(as, sccb, attrs, @@ -337,6 +338,7 @@ if (ret != MEMTX_OK) { return -PGM_ADDRESSING; } + work_sccb->h = header; if (!sclp_command_code_valid(code)) { work_sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
diff --git a/hw/s390x/sclpcpi.c b/hw/s390x/sclpcpi.c index 68fc1b8..ec4bdf2 100644 --- a/hw/s390x/sclpcpi.c +++ b/hw/s390x/sclpcpi.c
@@ -97,6 +97,11 @@ ebh); SCLPEventCPI *e = SCLP_EVENT_CPI(event); + /* Caller checks sccb length, buffer header checking is our duty */ + if (be16_to_cpu(evt_buf_hdr->length) != sizeof(ControlProgramIdMsg)) { + return SCLP_RC_INCONSISTENT_LENGTHS; + } + ascii_put(e->system_type, (char *)cpim->data.system_type, sizeof(cpim->data.system_type)); ascii_put(e->system_name, (char *)cpim->data.system_name,
diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index c69e247..895edcc 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c
@@ -285,6 +285,10 @@ b |= 0x04; } + if (len < 3) { + return 0; + } + buf[0] = b; buf[1] = dx; buf[2] = dy;
diff --git a/include/hw/misc/stm32_rcc.h b/include/hw/misc/stm32_rcc.h index 4dccacc..a94781b 100644 --- a/include/hw/misc/stm32_rcc.h +++ b/include/hw/misc/stm32_rcc.h
@@ -65,7 +65,11 @@ #define STM32_RCC_NREGS ((STM32_RCC_DCKCFGR2 >> 2) + 1) #define STM32_RCC_PERIPHERAL_SIZE 0x400 -#define STM32_RCC_NIRQS (32 * 5) /* 32 bits per reg, 5 en/rst regs */ + +/* 32 bits per reg, 3 AHB regs and 2 APB regs */ +#define STM32_RCC_N_AHB_IRQS (32 * 3) +#define STM32_RCC_N_APB_IRQS (32 * 2) +#define STM32_RCC_NIRQS (STM32_RCC_N_AHB_IRQS + STM32_RCC_N_APB_IRQS) #define STM32_RCC_GPIO_IRQ_OFFSET 0
diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index d332623..79b41f3 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h
@@ -132,6 +132,7 @@ bool ccw_fmt_1; bool thinint_active; uint8_t ccw_no_data_cnt; + uint8_t ccw_tic_cnt; uint16_t migrated_schid; /* used for mismatch detection */ CcwDataStream cds; /* transport-provided data: */
diff --git a/linux-user/alpha/elfload.c b/linux-user/alpha/elfload.c index 1969f62..7be9e46 100644 --- a/linux-user/alpha/elfload.c +++ b/linux-user/alpha/elfload.c
@@ -6,6 +6,17 @@ #include "target_elf.h" +abi_ulong get_elf_hwcap(CPUState *cs) +{ + /* + * The Linux kernel computes ELF_HWCAP as ~amask(-1), which clears a bit + * for each supported ISA extension. env->amask stores exactly those bits + * set for the extensions supported by the emulated CPU model, matching + * the kernel's convention: bit set in AT_HWCAP ↔ extension present. + */ + return cpu_env(cs)->amask; +} + void elf_core_copy_regs(target_elf_gregset_t *r, const CPUAlphaState *env) { int i;
diff --git a/linux-user/alpha/target_elf.h b/linux-user/alpha/target_elf.h index 4987ae3..dd90c6f 100644 --- a/linux-user/alpha/target_elf.h +++ b/linux-user/alpha/target_elf.h
@@ -12,6 +12,7 @@ #define ELF_MACHINE EM_ALPHA #define HAVE_ELF_CORE_DUMP 1 +#define HAVE_ELF_HWCAP 1 /* * Matches the kernel's elf_gregset_t (ELF_NGREG = 33):
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b3572a6..3da5530 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c
@@ -5088,6 +5088,9 @@ } #endif /* CONFIG_USBFS */ +#define DM_MAX_TARGETS 1048576 +#define DM_MAX_TARGET_PARAMS 1024 + static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, int cmd, abi_long arg) { @@ -5100,6 +5103,7 @@ abi_long ret; void *big_buf = NULL; char *host_data; + const size_t minimum_data_size = offsetof(struct dm_ioctl, data); arg_type++; target_size = thunk_type_size(arg_type, 0); @@ -5111,9 +5115,26 @@ thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); - /* buf_temp is too small, so fetch things into a bigger buffer */ - big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2); - memcpy(big_buf, buf_temp, target_size); + /* At this point this includes the size of the fixed dm_ioctl parts */ + guest_data_size = ((struct dm_ioctl *)buf_temp)->data_size; + + if (guest_data_size < minimum_data_size || + guest_data_size > DM_MAX_TARGETS * DM_MAX_TARGET_PARAMS) { + ret = -TARGET_EINVAL; + goto out; + } + + /* + * buf_temp is too small, so fetch things into a bigger buffer. Here + * we copy all of the fixed parts of struct dm_ioctl but not the + * data at the end (which in the struct is "char data[7]" but in + * reality is command-specific and might be nothing or might be + * much larger, as defined by data_size). We know struct dm_ioctl's + * size is not target specific so we don't need to distinguish between + * its minimum size for the host vs the target. + */ + big_buf = g_malloc0(guest_data_size * 2); + memcpy(big_buf, buf_temp, minimum_data_size); buf_temp = big_buf; host_dm = big_buf; @@ -5122,7 +5143,8 @@ ret = -TARGET_EINVAL; goto out; } - guest_data_size = host_dm->data_size - host_dm->data_start; + /* Adjust down to only the size of the payload */ + guest_data_size -= host_dm->data_start; host_data = (char*)host_dm + host_dm->data_start; argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
diff --git a/contrib/gitdm/aliases b/scripts/gitdm/aliases similarity index 96% rename from contrib/gitdm/aliases rename to scripts/gitdm/aliases index e26b00a..f838768 100644 --- a/contrib/gitdm/aliases +++ b/scripts/gitdm/aliases
@@ -33,6 +33,7 @@ # canonical emails liq3ea@163.com liq3ea@gmail.com +aleksandr.mikhalitsyn@futurfusion.io alexander@mihalicyn.com # some broken DCO tags yuval.shaia.ml.gmail.com yuval.shaia.ml@gmail.com
diff --git a/contrib/gitdm/domain-map b/scripts/gitdm/domain-map similarity index 93% rename from contrib/gitdm/domain-map rename to scripts/gitdm/domain-map index c07dffc..aef20c4 100644 --- a/contrib/gitdm/domain-map +++ b/scripts/gitdm/domain-map
@@ -40,7 +40,8 @@ nvidia.com NVIDIA oracle.com Oracle proxmox.com Proxmox -quicinc.com Qualcomm Innovation Center +oss.qualcomm.com Qualcomm Technologies, Inc. +quicinc.com Qualcomm Technologies, Inc. redhat.com Red Hat rev.ng rev.ng Labs rivosinc.com Rivos Inc
diff --git a/contrib/gitdm/filetypes.txt b/scripts/gitdm/filetypes.txt similarity index 100% rename from contrib/gitdm/filetypes.txt rename to scripts/gitdm/filetypes.txt
diff --git a/contrib/gitdm/group-map-academics b/scripts/gitdm/group-map-academics similarity index 100% rename from contrib/gitdm/group-map-academics rename to scripts/gitdm/group-map-academics
diff --git a/contrib/gitdm/group-map-alibaba b/scripts/gitdm/group-map-alibaba similarity index 100% rename from contrib/gitdm/group-map-alibaba rename to scripts/gitdm/group-map-alibaba
diff --git a/contrib/gitdm/group-map-amd b/scripts/gitdm/group-map-amd similarity index 100% rename from contrib/gitdm/group-map-amd rename to scripts/gitdm/group-map-amd
diff --git a/contrib/gitdm/group-map-cadence b/scripts/gitdm/group-map-cadence similarity index 100% rename from contrib/gitdm/group-map-cadence rename to scripts/gitdm/group-map-cadence
diff --git a/contrib/gitdm/group-map-codeweavers b/scripts/gitdm/group-map-codeweavers similarity index 100% rename from contrib/gitdm/group-map-codeweavers rename to scripts/gitdm/group-map-codeweavers
diff --git a/contrib/gitdm/group-map-facebook b/scripts/gitdm/group-map-facebook similarity index 100% rename from contrib/gitdm/group-map-facebook rename to scripts/gitdm/group-map-facebook
diff --git a/contrib/gitdm/group-map-huawei b/scripts/gitdm/group-map-huawei similarity index 100% rename from contrib/gitdm/group-map-huawei rename to scripts/gitdm/group-map-huawei
diff --git a/scripts/gitdm/group-map-ibm b/scripts/gitdm/group-map-ibm new file mode 100644 index 0000000..39c53a4 --- /dev/null +++ b/scripts/gitdm/group-map-ibm
@@ -0,0 +1,7 @@ +# +# Some IBM contributors submit via another domain +# + +jcfaracco@gmail.com +tommusta@gmail.com +idan.horowitz@gmail.com
diff --git a/contrib/gitdm/group-map-individuals b/scripts/gitdm/group-map-individuals similarity index 95% rename from contrib/gitdm/group-map-individuals rename to scripts/gitdm/group-map-individuals index 178b393..190941b 100644 --- a/contrib/gitdm/group-map-individuals +++ b/scripts/gitdm/group-map-individuals
@@ -46,3 +46,5 @@ me@sean.taipei kosasihwilliam4@gmail.com philmd@mailo.com +tomitamoeko@gmail.com +neither@nut.email
diff --git a/contrib/gitdm/group-map-interns b/scripts/gitdm/group-map-interns similarity index 100% rename from contrib/gitdm/group-map-interns rename to scripts/gitdm/group-map-interns
diff --git a/contrib/gitdm/group-map-janustech b/scripts/gitdm/group-map-janustech similarity index 100% rename from contrib/gitdm/group-map-janustech rename to scripts/gitdm/group-map-janustech
diff --git a/contrib/gitdm/group-map-microsoft b/scripts/gitdm/group-map-microsoft similarity index 100% rename from contrib/gitdm/group-map-microsoft rename to scripts/gitdm/group-map-microsoft
diff --git a/contrib/gitdm/group-map-netflix b/scripts/gitdm/group-map-netflix similarity index 100% rename from contrib/gitdm/group-map-netflix rename to scripts/gitdm/group-map-netflix
diff --git a/contrib/gitdm/group-map-redhat b/scripts/gitdm/group-map-redhat similarity index 100% rename from contrib/gitdm/group-map-redhat rename to scripts/gitdm/group-map-redhat
diff --git a/contrib/gitdm/group-map-robots b/scripts/gitdm/group-map-robots similarity index 100% rename from contrib/gitdm/group-map-robots rename to scripts/gitdm/group-map-robots
diff --git a/contrib/gitdm/group-map-wavecomp b/scripts/gitdm/group-map-wavecomp similarity index 100% rename from contrib/gitdm/group-map-wavecomp rename to scripts/gitdm/group-map-wavecomp
diff --git a/target/arm/cpu-max.c b/target/arm/cpu-max.c index d38bdfc..88b7c04 100644 --- a/target/arm/cpu-max.c +++ b/target/arm/cpu-max.c
@@ -130,7 +130,7 @@ t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* FEAT_TTCNP */ t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX */ - t = FIELD_DP32(t, ID_MMFR4, EVT, 2); /* FEAT_EVT */ + t = FIELD_DP32(t, ID_MMFR4, EVT, 2); /* FEAT_EVT2 */ SET_IDREG(isar, ID_MMFR4, t); FIELD_DP32_IDREG(isar, ID_MMFR5, ETS, 2); /* FEAT_ETS2 */
diff --git a/target/arm/tcg/tlb-insns.c b/target/arm/tcg/tlb-insns.c index 1a0a332..b24eb57 100644 --- a/target/arm/tcg/tlb-insns.c +++ b/target/arm/tcg/tlb-insns.c
@@ -854,7 +854,7 @@ gran = tlbi_range_tg_to_gran_size(page_size_granule); /* The granule encoded in value must match the granule in use. */ - if (gran != param.gran) { + if (gran != param.gran || gran == GranInvalid) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid tlbi page size granule %d\n", page_size_granule); return ret;
diff --git a/tests/functional/riscv64/meson.build b/tests/functional/riscv64/meson.build index c9d4c09..d1a3e6c 100644 --- a/tests/functional/riscv64/meson.build +++ b/tests/functional/riscv64/meson.build
@@ -2,6 +2,7 @@ test_riscv64_timeouts = { 'boston' : 120, + 'k230' : 120, 'tuxrun' : 120, } @@ -13,6 +14,7 @@ tests_riscv64_system_thorough = [ 'endianness', 'boston', + 'k230', 'sifive_u', 'tt_atlantis', 'tuxrun',
diff --git a/tests/functional/riscv64/test_k230.py b/tests/functional/riscv64/test_k230.py new file mode 100755 index 0000000..6ccbf2d --- /dev/null +++ b/tests/functional/riscv64/test_k230.py
@@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# +# Functional tests that boot Linux on a Kendryte K230 machine. +# +# The direct boot test lets QEMU load OpenSBI, Linux, the device tree, and the +# initramfs. The firmware boot test starts the K230 SDK U-Boot and uses bootm +# to launch OpenSBI and Linux from images preloaded into RAM. +# +# Author: +# Junze Cao +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os + +from qemu_test import Asset, LinuxKernelTest +from qemu_test import exec_command_and_wait_for_pattern +from qemu_test import interrupt_interactive_console_until_pattern + + +class K230Machine(LinuxKernelTest): + + ASSET_KERNEL = Asset( + ('https://raw.githubusercontent.com/zevorn/k230-boot-assets/' + 'c3c32fb46e8307c5063f13e8f367c98bf9273cd1/' + 'yocto/direct-boot/Image'), + '3a44970213fa68ad318d308518adfc0bf4bee72ed1b2926f9b468f82ef7d7829') + ASSET_DTB = Asset( + ('https://raw.githubusercontent.com/zevorn/k230-boot-assets/' + 'c3c32fb46e8307c5063f13e8f367c98bf9273cd1/' + 'yocto/direct-boot/k230-canmv.dtb'), + '5050240b48ce0988c73eaefa73e4945a40abca503cf488d22a3adf6ef50bbe4c') + ASSET_INITRD = Asset( + ('https://raw.githubusercontent.com/zevorn/k230-boot-assets/' + 'c3c32fb46e8307c5063f13e8f367c98bf9273cd1/' + 'yocto/direct-boot/rootfs.cpio.gz'), + '4e1869a99a232ee60324f71f3a9e84a79b03ccabb5b73f8a727c5ff5be5c0914') + ASSET_UBOOT = Asset( + ('https://raw.githubusercontent.com/zevorn/k230-boot-assets/' + 'c3c32fb46e8307c5063f13e8f367c98bf9273cd1/common/u-boot'), + '0915b9a92a7c911846a8cf691866ef14ef050a51d04209f884ae8e9ec33f36d2') + ASSET_FW_JUMP = Asset( + ('https://raw.githubusercontent.com/zevorn/k230-boot-assets/' + 'c3c32fb46e8307c5063f13e8f367c98bf9273cd1/' + 'common/fw_jump.uImage'), + 'cf7788e470f1d6e8c85491ecdc2705518db1b6af54080e8c7a3464bad0d902b7') + + def wait_for_linux_shell(self): + self.wait_for_console_pattern('meta-k230 initramfs starting...') + self.wait_for_console_pattern('~ #') + + def test_k230_direct_boot(self): + self.set_machine('k230') + kernel_path = self.ASSET_KERNEL.fetch() + dtb_path = self.ASSET_DTB.fetch() + initrd_path = self.ASSET_INITRD.fetch() + + self.vm.set_console() + self.vm.add_args('-kernel', kernel_path, + '-dtb', dtb_path, + '-initrd', initrd_path, + '-append', 'console=ttyS0,115200 earlycon=sbi', + '-no-reboot') + self.vm.launch() + self.wait_for_linux_shell() + + def test_k230_uboot_boot(self): + self.set_machine('k230') + kernel_path = self.ASSET_KERNEL.fetch() + dtb_path = self.ASSET_DTB.fetch() + initrd_path = self.ASSET_INITRD.fetch() + uboot_path = self.ASSET_UBOOT.fetch() + fw_jump_path = self.ASSET_FW_JUMP.fetch() + initrd_end = 0x0a100000 + os.path.getsize(initrd_path) + + self.vm.set_console() + self.vm.add_args( + '-bios', uboot_path, + '-device', + f'loader,file={fw_jump_path},addr=0xc100000,force-raw=on', + '-device', + f'loader,file={kernel_path},addr=0x8200000,force-raw=on', + '-device', + f'loader,file={initrd_path},addr=0xa100000,force-raw=on', + '-device', + f'loader,file={dtb_path},addr=0xa000000,force-raw=on', + '-no-reboot') + self.vm.launch() + + interrupt_interactive_console_until_pattern(self, 'K230#') + commands = ( + 'setenv bootargs console=ttyS0,115200 earlycon=sbi', + 'fdt addr 0xa000000', + 'fdt resize 8192', + 'fdt set /chosen linux,initrd-start <0x0 0xa100000>', + f'fdt set /chosen linux,initrd-end <0x0 0x{initrd_end:x}>', + ) + for command in commands: + exec_command_and_wait_for_pattern(self, command, 'K230#') + + exec_command_and_wait_for_pattern( + self, 'bootm 0xc100000 - 0xa000000', + 'Starting kernel ...', failure_message='ERROR') + self.wait_for_linux_shell() + + +if __name__ == '__main__': + LinuxKernelTest.main()
diff --git a/tests/functional/riscv64/test_sifive_u.py b/tests/functional/riscv64/test_sifive_u.py index 847f709..54a0f9c 100755 --- a/tests/functional/riscv64/test_sifive_u.py +++ b/tests/functional/riscv64/test_sifive_u.py
@@ -35,9 +35,6 @@ def do_test_riscv64_sifive_u_mmc_spi(self, connect_card): kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 'earlycon=sbi console=ttySIF0 ' 'root=/dev/mmcblk0 ') - self.vm.add_args('-kernel', kernel_path, - '-append', kernel_command_line, - '-no-reboot') if connect_card: kernel_command_line += 'panic=-1 noreboot rootwait ' self.vm.add_args('-drive', f'file={rootfs_path},if=sd,format=raw') @@ -46,6 +43,9 @@ def do_test_riscv64_sifive_u_mmc_spi(self, connect_card): kernel_command_line += 'panic=0 noreboot ' pattern = 'Cannot open root device "mmcblk0" or unknown-block(0,0)' + self.vm.add_args('-kernel', kernel_path, + '-append', kernel_command_line, + '-no-reboot') self.vm.launch() self.wait_for_console_pattern(pattern)
diff --git a/tests/qtest/adm1266-test.c b/tests/qtest/adm1266-test.c index 5ae8206..726e475 100644 --- a/tests/qtest/adm1266-test.c +++ b/tests/qtest/adm1266-test.c
@@ -48,11 +48,13 @@ static void compare_string(QI2CDevice *i2cdev, uint8_t reg, const char *test_str) { - uint8_t len = i2c_get8(i2cdev, reg); - char i2c_str[SMBUS_DATA_MAX_LEN] = {0}; + uint8_t expected_len = strlen(test_str); + uint8_t resp[SMBUS_DATA_MAX_LEN] = {0}; - i2c_read_block(i2cdev, reg, (uint8_t *)i2c_str, len); - g_assert_cmpstr(i2c_str, ==, test_str); + g_assert(expected_len + 1 < SMBUS_DATA_MAX_LEN); + i2c_read_block(i2cdev, reg, resp, expected_len + 1); + g_assert_cmpint(resp[0], ==, expected_len); + g_assert_cmpstr((char *)resp + 1, ==, test_str); } static void write_and_compare_string(QI2CDevice *i2cdev, uint8_t reg,