* [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa
@ 2026-06-07 14:03 Helge Deller
2026-06-07 14:03 ` [PATCH 01/10] linux-user: implement fsmount(2) series of syscalls Helge Deller
` (9 more replies)
0 siblings, 10 replies; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller
From: Helge Deller <deller@gmx.de>
Various linux-user related patches from Matt Turner with coredump support for
alpha and sparc, as well as some fixes for the signal handler in sparc and
xtensa.
The patches from Xinhui Yang add the missing fsmount series syscalls support
for systemd.
Especially the sparc and xtensa patches would benefit from a review, as I'm not an
expert in those architectures.
Matt Turner (8):
linux-user/alpha: add coredump support
linux-user/sparc: add coredump support
linux-user/sparc: restore L/I registers from RSA in
sparc64_set_context
linux-user/sparc: call block_signals() before set_sigmask() in
setcontext
linux-user/sparc: flush register windows before core dump
target/sh4: decode_gusa: recognize add#imm with prior mov Rm, Rn
linux-user/xtensa: restore FP rounding mode on sigreturn
target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status
Xinhui Yang (2):
linux-user: implement fsmount(2) series of syscalls
linux-user/strace: add fsmount series of syscalls
linux-user/alpha/elfload.c | 12 ++++
linux-user/alpha/target_elf.h | 13 +++++
linux-user/elfload.c | 9 +++
linux-user/sparc/cpu_loop.c | 3 +-
linux-user/sparc/cpu_loop.h | 7 +++
linux-user/sparc/elfload.c | 54 +++++++++++++++++
linux-user/sparc/signal.c | 27 +++++++++
linux-user/sparc/target_elf.h | 20 +++++++
linux-user/strace.c | 105 ++++++++++++++++++++++++++++++++++
linux-user/strace.list | 15 +++++
linux-user/syscall.c | 91 +++++++++++++++++++++++++++++
linux-user/xtensa/signal.c | 36 ++++++++++--
target/sh4/translate.c | 2 +-
target/xtensa/cpu.h | 4 ++
target/xtensa/fpu_helper.c | 42 ++++++++++++++
15 files changed, 433 insertions(+), 7 deletions(-)
create mode 100644 linux-user/sparc/cpu_loop.h
--
2.54.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 01/10] linux-user: implement fsmount(2) series of syscalls
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
@ 2026-06-07 14:03 ` Helge Deller
2026-06-07 14:03 ` [PATCH 02/10] linux-user/strace: add fsmount " Helge Deller
` (8 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller, Xinhui Yang
From: Xinhui Yang <cyan@cyano.uk>
This series of syscalls replaces the old mount(2) syscall with a series
of syscalls that operates around a filesystem context. This series of
syscalls is available since Linux 5.2 and glibc 2.36+.
Their users include systemd since v259 and libmount from util-linux, and
possibly other widely used projects.
Preliminary checks are implemented to ensure the validity of the
interface.
Signed-off-by: Xinhui Yang <cyan@cyano.uk>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Helge Deller <deller@gmx.de>
---
linux-user/syscall.c | 91 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 7d7a7b489c..c5c2aa80ec 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -14412,6 +14412,97 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return do_map_shadow_stack(cpu_env, arg1, arg2, arg3);
#endif
+#if defined(TARGET_NR_fsopen)
+ case TARGET_NR_fsopen:
+ {
+ p = lock_user_string(arg1);
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(fsopen(p, arg2));
+ unlock_user(p, arg1, 0);
+ }
+ return ret;
+ case TARGET_NR_fsconfig:
+ {
+ /*
+ * fsconfig(int, int, char *, void *, int)
+ * NOTE: p4 is nullable and its type might not be a string.
+ */
+ void *p3, *p4;
+ int cmd = (int) arg2;
+ switch (cmd) {
+ case FSCONFIG_SET_BINARY:
+ case FSCONFIG_SET_STRING:
+ case FSCONFIG_SET_PATH:
+ case FSCONFIG_SET_PATH_EMPTY:
+ p3 = lock_user_string(arg3);
+ if (!p3) {
+ return -TARGET_EFAULT;
+ }
+ if (cmd != FSCONFIG_SET_BINARY) {
+ /* key and value must be strings. */
+ p4 = lock_user_string(arg4);
+ } else {
+ /*
+ * Otherwise the value must be a raw buffer with its
+ * length specified in arg5 (aux).
+ */
+ p4 = lock_user(VERIFY_READ, arg4, arg5, 1);
+ }
+ if (!p4) {
+ unlock_user(p3, arg3, 0);
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(fsconfig(arg1, arg2, p3, p4, arg5));
+ unlock_user(p3, arg3, 0);
+ unlock_user(p4, arg4, 0);
+ break;
+
+ case FSCONFIG_SET_FLAG:
+ case FSCONFIG_SET_FD:
+ /* arg4 (value) must be NULL. */
+ if (arg4) {
+ return -TARGET_EFAULT;
+ }
+ p3 = lock_user_string(arg3);
+ if (!p3) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(fsconfig(arg1, arg2, p3, NULL, arg5));
+ unlock_user(p3, arg3, 0);
+ break;
+ case FSCONFIG_CMD_CREATE:
+ case FSCONFIG_CMD_RECONFIGURE:
+#ifdef FSCONFIG_CMD_CREATE_EXCL
+ /*
+ * FSCONFIG_CMD_CREATE_EXCL is only available since Linux
+ * 6.6. Guarding it to allow building with pre-6.6 headers.
+ */
+ case FSCONFIG_CMD_CREATE_EXCL:
+#endif
+ /* key and value must be NULL, aux must be 0. */
+ if (arg3 || arg4 || arg5) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(fsconfig(arg1, arg2, NULL, NULL, 0));
+ break;
+ default:
+ return -TARGET_EFAULT;
+ }
+ }
+ return ret;
+ case TARGET_NR_fsmount:
+ ret = get_errno(fsmount(arg1, arg2, arg3));
+ return ret;
+ case TARGET_NR_fspick:
+ {
+ p = lock_user_string(arg2);
+ ret = get_errno(fspick(arg1, p, arg3));
+ unlock_user(p, arg2, 0);
+ }
+ return ret;
+#endif
default:
qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
return -TARGET_ENOSYS;
--
2.54.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 02/10] linux-user/strace: add fsmount series of syscalls
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
2026-06-07 14:03 ` [PATCH 01/10] linux-user: implement fsmount(2) series of syscalls Helge Deller
@ 2026-06-07 14:03 ` Helge Deller
2026-06-07 14:03 ` [PATCH 03/10] linux-user/alpha: add coredump support Helge Deller
` (7 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller, Xinhui Yang
From: Xinhui Yang <cyan@cyano.uk>
Following the addition of fsmount(2) series of syscalls in the syscall
handler, strace support is added, with a dedicated function to print the
parameters of fsconfig(2), which contains parameters that can be
interpreted as multiple types.
Snippet of the strace dump when running `mount -t tmpfs tmpfs /media`:
18 fsopen(tmpfs,1) = 3
18 read(3,0x407fcf1c,8191) = -1 errno=61 (No data available)
18 fsconfig(3,FSCONFIG_SET_STRING,"source","tmpfs",0) = 0
18 read(3,0x407fce3c,8191) = -1 errno=61 (No data available)
18 fsconfig(3,FSCONFIG_CMD_CREATE,NULL,NULL,0) = 0
18 read(3,0x407fce3c,8191) = -1 errno=61 (No data available)
18 fsmount(3,1,0) = 4
18 read(3,0x407fce3c,8191) = -1 errno=61 (No data available)
18 statx(4,"",AT_EMPTY_PATH|AT_STATX_SYNC_AS_STAT,0x1000,0x407fee98) = 0
18 move_mount(4,,-100,/media,4) = 0
18 read(3,0x407fcfcc,8191) = -1 errno=61 (No data available)
18 close(3) = 0
18 close(4) = 0
Signed-off-by: Xinhui Yang <cyan@cyano.uk>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Helge Deller <deller@gmx.de>
---
linux-user/strace.c | 105 +++++++++++++++++++++++++++++++++++++++++
linux-user/strace.list | 15 ++++++
2 files changed, 120 insertions(+)
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 2cbaf94c89..d861f311f6 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -4344,6 +4344,111 @@ print_statx(CPUArchState *cpu_env, const struct syscallname *name,
}
#endif
+#ifdef TARGET_NR_fsconfig
+static void
+print_fsconfig_cmd_name(int cmd)
+{
+ switch (cmd) {
+ case FSCONFIG_SET_FLAG:
+ qemu_log("%s%s", "FSCONFIG_SET_FLAG", get_comma(0));
+ break;
+ case FSCONFIG_SET_STRING:
+ qemu_log("%s%s", "FSCONFIG_SET_STRING", get_comma(0));
+ break;
+ case FSCONFIG_SET_BINARY:
+ qemu_log("%s%s", "FSCONFIG_SET_BINARY", get_comma(0));
+ break;
+ case FSCONFIG_SET_PATH:
+ qemu_log("%s%s", "FSCONFIG_SET_PATH", get_comma(0));
+ break;
+ case FSCONFIG_SET_PATH_EMPTY:
+ qemu_log("%s%s", "FSCONFIG_SET_PATH_EMPTY", get_comma(0));
+ break;
+ case FSCONFIG_SET_FD:
+ qemu_log("%s%s", "FSCONFIG_SET_FD", get_comma(0));
+ break;
+ case FSCONFIG_CMD_CREATE:
+ qemu_log("%s%s", "FSCONFIG_CMD_CREATE", get_comma(0));
+ break;
+ case FSCONFIG_CMD_RECONFIGURE:
+ qemu_log("%s%s", "FSCONFIG_CMD_RECONFIGURE", get_comma(0));
+ break;
+#ifdef FSCONFIG_CMD_CREATE_EXCL
+ case FSCONFIG_CMD_CREATE_EXCL:
+ /* Only available since Linux 6.6. */
+ qemu_log("%s%s", "FSCONFIG_CMD_CREATE_EXCL", get_comma(0));
+ break;
+#endif
+ default:
+ qemu_log("%s (%d)%s", "UNKNOWN_CMD", cmd, get_comma(0));
+ break;
+ }
+}
+
+static void
+print_fsconfig(CPUArchState *cpu_env, const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ /*
+ * fsconfig(int fd, int cmd, char* key, void* value, int aux)
+ * Where:
+ * fd: file descriptor returned by fsopen().
+ * cmd: integer constant specifying a command.
+ * key: a string, can be NULL on certain commands.
+ * value: any data in a buffer, can be NULL, raw buffer or a string.
+ * aux: axillary values such as flags for FSCONFIG_SET_PATH.
+ */
+ int cmd = (int) arg1;
+ print_syscall_prologue(name);
+ print_raw_param("%d", arg0, 0);
+ print_fsconfig_cmd_name(cmd);
+ /* Process arg2 (key). */
+ switch (cmd) {
+ case FSCONFIG_SET_FLAG:
+ case FSCONFIG_SET_STRING:
+ case FSCONFIG_SET_BINARY:
+ case FSCONFIG_SET_PATH:
+ case FSCONFIG_SET_PATH_EMPTY:
+ case FSCONFIG_SET_FD:
+ print_string(arg2, 0);
+ break;
+ default:
+ print_pointer(arg2, 0);
+ break;
+ }
+ /* Process arg3 (value). */
+ switch (cmd) {
+ case FSCONFIG_SET_STRING:
+ case FSCONFIG_SET_PATH:
+ case FSCONFIG_SET_PATH_EMPTY:
+ print_string(arg3, 0);
+ break;
+ default:
+ print_pointer(arg3, 0);
+ break;
+ }
+ /*
+ * Process arg4 (aux).
+ * On FSCONFIG_SET_PATH and FSCONFIG_SET_PATH_EMPTY, aux can
+ * be either 0 or AT_FDCWD.
+ * On FSCONFIG_SET_BINARY, aux is an integer to state the length
+ * of the buffer pointed by arg3.
+ * Otherwise, it must be 0.
+ */
+ switch (cmd) {
+ case FSCONFIG_SET_PATH:
+ case FSCONFIG_SET_PATH_EMPTY:
+ print_at_dirfd(arg4, 1);
+ break;
+ default:
+ print_raw_param("%d", arg4, 1);
+ break;
+ }
+ print_syscall_epilogue(name);
+}
+#endif
+
#ifdef TARGET_NR_ioctl
static void
print_ioctl(CPUArchState *cpu_env, const struct syscallname *name,
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 6162a407f9..3a366b8cac 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1722,3 +1722,18 @@
#ifdef TARGET_NR_rseq
{ TARGET_NR_rseq, "rseq" , "%s(%p,%u,%d,%#x)", NULL, NULL },
#endif
+#ifdef TARGET_NR_fsopen
+{ TARGET_NR_fsopen, "fsopen", "%s(%s,%d)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_fsconfig
+{ TARGET_NR_fsconfig, "fsconfig", NULL, print_fsconfig, NULL },
+#endif
+#ifdef TARGET_NR_fsmount
+{ TARGET_NR_fsmount, "fsmount", "%s(%d,%d,%d)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_move_mount
+{ TARGET_NR_move_mount, "move_mount", "%s(%d,%s,%d,%s,%d)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_fspick
+{ TARGET_NR_fspick, "fspick", "%s(%d,%s,%d)", NULL, NULL },
+#endif
--
2.54.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 03/10] linux-user/alpha: add coredump support
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
2026-06-07 14:03 ` [PATCH 01/10] linux-user: implement fsmount(2) series of syscalls Helge Deller
2026-06-07 14:03 ` [PATCH 02/10] linux-user/strace: add fsmount " Helge Deller
@ 2026-06-07 14:03 ` Helge Deller
2026-06-07 15:30 ` Richard Henderson
2026-06-07 14:03 ` [PATCH 04/10] linux-user/sparc: " Helge Deller
` (6 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller, Matt Turner
From: Matt Turner <mattst88@gmail.com>
Define HAVE_ELF_CORE_DUMP and target_elf_gregset_t in target_elf.h,
mirroring the kernel's elf_gregset_t (ELF_NGREG = 66): r0-r31
[0..31], f0-f31 [32..63], pc [64], unique [65]. Implement
elf_core_copy_regs() in elfload.c to populate the gregset from
CPUAlphaState.
Without this, bprm->core_dump is NULL for Alpha targets. When a
guest signal goes unhandled, dump_core_and_abort() skips the core
write and falls through to die_with_signal(), which re-raises the
signal to the host. The host kernel then writes an x86-64 core file
for the qemu-alpha process instead of an Alpha guest core.
v2: Store thread unique field, same as in Linux kernel. Added by Helge &
suggested by Richard.
Signed-off-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Helge Deller <deller@gmx.de>
---
linux-user/alpha/elfload.c | 12 ++++++++++++
linux-user/alpha/target_elf.h | 13 +++++++++++++
2 files changed, 25 insertions(+)
diff --git a/linux-user/alpha/elfload.c b/linux-user/alpha/elfload.c
index 1e44475c47..d2aed15ce5 100644
--- a/linux-user/alpha/elfload.c
+++ b/linux-user/alpha/elfload.c
@@ -3,8 +3,20 @@
#include "qemu/osdep.h"
#include "qemu.h"
#include "loader.h"
+#include "target_elf.h"
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUAlphaState *env)
+{
+ int i;
+
+ for (i = 0; i < 31; i++) {
+ r->regs[i] = tswap64(env->ir[i]);
+ }
+ r->pc = tswap64(env->pc);
+ r->unique = env->unique;
+}
+
const char *get_elf_cpu_model(uint32_t eflags)
{
return "ev67";
diff --git a/linux-user/alpha/target_elf.h b/linux-user/alpha/target_elf.h
index 864dc6e2e6..4987ae3944 100644
--- a/linux-user/alpha/target_elf.h
+++ b/linux-user/alpha/target_elf.h
@@ -11,4 +11,17 @@
#define ELF_CLASS ELFCLASS64
#define ELF_MACHINE EM_ALPHA
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * Matches the kernel's elf_gregset_t (ELF_NGREG = 33):
+ * r0-r30 at indices 0-30, pc at 31, ps at 32.
+ * r31 (hardwired zero) is not stored; pc occupies index 31.
+ */
+typedef struct target_elf_gregset_t {
+ abi_ulong regs[31]; /* integer registers r0-r30 [0..30] */
+ abi_ulong pc; /* program counter [31] */
+ abi_ulong unique; /* thread's UNIQUE field [32] */
+} target_elf_gregset_t;
+
#endif
--
2.54.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 04/10] linux-user/sparc: add coredump support
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
` (2 preceding siblings ...)
2026-06-07 14:03 ` [PATCH 03/10] linux-user/alpha: add coredump support Helge Deller
@ 2026-06-07 14:03 ` Helge Deller
2026-06-07 14:03 ` [PATCH 05/10] linux-user/sparc: restore L/I registers from RSA in sparc64_set_context Helge Deller
` (5 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller, Matt Turner, Mark Cave-Ayland
From: Matt Turner <mattst88@gmail.com>
Define HAVE_ELF_CORE_DUMP and target_elf_gregset_t in target_elf.h
sized to match the kernel's elf_gregset_t:
sparc32/sparc32plus (ELF_NGREG = 38):
[0] PSR
[1] PC
[2] NPC
[3] Y
[4..11] G0-G7
[12..19] O0-O7
[20..27] L0-L7
[28..35] I0-I7
[36..37] reserved (stack_check)
sparc64 (ELF_NGREG = 36):
[0..7] G0-G7
[8..15] O0-O7
[16..23] L0-L7
[24..31] I0-I7
[32] TSTATE
[33] TPC
[34] TNPC
[35] Y
Also define ELF_MACHINE as EM_SPARC32PLUS for TARGET_ABI32 builds,
matching the kernel and ensuring the correct machine type appears in
the core file.
Implement elf_core_copy_regs() in elfload.c to populate the gregset
from CPUSPARCState, including L0-L7 and I0-I7 from env->regwptr.
A memset() at entry zeros the trailing reserved slots.
Without this, bprm->core_dump is NULL for SPARC targets. When a
guest signal goes unhandled, dump_core_and_abort() skips the core
write and falls through to die_with_signal(), which re-raises the
signal to the host. The host kernel then writes an x86-64 core file
for the qemu-sparc process instead of a SPARC guest core.
Populating the full register layout is required for tools like
libunwind-coredump, which reads pr_reg[33] for the trap PC and
pr_reg[16..31] for the windowed registers.
Signed-off-by: Matt Turner <mattst88@gmail.com>
Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Helge Deller <deller@gmx.de>
---
linux-user/sparc/elfload.c | 27 +++++++++++++++++++++++++++
linux-user/sparc/target_elf.h | 11 +++++++++++
2 files changed, 38 insertions(+)
diff --git a/linux-user/sparc/elfload.c b/linux-user/sparc/elfload.c
index 32ca1b05b1..e6387ec891 100644
--- a/linux-user/sparc/elfload.c
+++ b/linux-user/sparc/elfload.c
@@ -4,8 +4,35 @@
#include "qemu.h"
#include "loader.h"
#include "elf.h"
+#include "target_elf.h"
+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUArchState *env)
+{
+ CPUSPARCState *e = (CPUSPARCState *)env;
+ int i;
+
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ for (i = 0; i < 8; i++) {
+ r->regs[i] = tswap64(env->gregs[i]);
+ r->regs[8 + i] = tswap64(env->regwptr[WREG_O0 + i]);
+ }
+ r->regs[16] = tswap64(sparc64_tstate(e));
+ r->regs[17] = tswap64(env->pc);
+ r->regs[18] = tswap64(env->npc);
+ r->regs[19] = tswap64(env->y);
+#else
+ r->regs[0] = tswap32(cpu_get_psr(e));
+ r->regs[1] = tswap32(env->pc);
+ r->regs[2] = tswap32(env->npc);
+ r->regs[3] = tswap32(env->y);
+ for (i = 0; i < 8; i++) {
+ r->regs[4 + i] = tswap32(env->gregs[i]);
+ r->regs[12 + i] = tswap32(env->regwptr[WREG_O0 + i]);
+ }
+#endif
+}
+
const char *get_elf_cpu_model(uint32_t eflags)
{
#ifdef TARGET_SPARC64
diff --git a/linux-user/sparc/target_elf.h b/linux-user/sparc/target_elf.h
index 7827767bcb..edb0b3103c 100644
--- a/linux-user/sparc/target_elf.h
+++ b/linux-user/sparc/target_elf.h
@@ -13,6 +13,7 @@
# define ELF_MACHINE EM_SPARC
#elif defined(TARGET_ABI32)
# define ELF_CLASS ELFCLASS32
+# define ELF_MACHINE EM_SPARC32PLUS
# define elf_check_machine(x) ((x) == EM_SPARC32PLUS || (x) == EM_SPARC)
#else
# define ELF_CLASS ELFCLASS64
@@ -20,5 +21,15 @@
#endif
#define HAVE_ELF_HWCAP 1
+#define HAVE_ELF_CORE_DUMP 1
+
+/*
+ * Matches the kernel's elf_gregset_t (ELF_NGREG = 20).
+ * sparc32/sparc32plus: psr, pc, npc, y, u_regs[16] (g0-g7, o0-o7)
+ * sparc64: u_regs[16] (g0-g7, o0-o7), tstate, pc, npc, y
+ */
+typedef struct target_elf_gregset_t {
+ abi_ulong regs[20];
+} target_elf_gregset_t;
#endif
--
2.54.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 05/10] linux-user/sparc: restore L/I registers from RSA in sparc64_set_context
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
` (3 preceding siblings ...)
2026-06-07 14:03 ` [PATCH 04/10] linux-user/sparc: " Helge Deller
@ 2026-06-07 14:03 ` Helge Deller
2026-06-07 14:03 ` [PATCH 06/10] linux-user/sparc: call block_signals() before set_sigmask() in setcontext Helge Deller
` (4 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller, Matt Turner, Mark Cave-Ayland
From: Matt Turner <mattst88@gmail.com>
The kernel's do_rt_sigreturn loads L and I registers from the register
save area (RSA) at the restored O6+STACK_BIAS. QEMU lacks the kernel's
window-fill path, so restore L0-L7 and I0-I5 explicitly from the RSA.
I6 and I7 are already restored from mc_fp/mc_i7.
Signed-off-by: Matt Turner <mattst88@gmail.com>
Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Helge Deller <deller@gmx.de>
---
linux-user/sparc/signal.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
index d339f89928..fda5508c48 100644
--- a/linux-user/sparc/signal.c
+++ b/linux-user/sparc/signal.c
@@ -656,6 +656,24 @@ void sparc64_set_context(CPUSPARCState *env)
__get_user(env->regwptr[WREG_FP], &(ucp->tuc_mcontext.mc_fp));
__get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7));
+ /*
+ * The kernel's do_rt_sigreturn loads L and I registers from the
+ * register save area (RSA) at the new O6+STACK_BIAS. Unlike the
+ * kernel, QEMU has no kernel-mode path that triggers a window fill,
+ * so we must do it explicitly here. I6 and I7 are already restored
+ * from mc_fp and mc_i7 above; restore L0-L7 and I0-I5 from the RSA.
+ */
+ {
+ abi_ulong sp_ptr = env->regwptr[WREG_O6];
+ /* LP64 O6 is biased (8-byte-aligned - 2047); low bit set. ILP32 O6 is 4-byte-aligned. */
+ if (sp_ptr & 3)
+ sp_ptr += TARGET_STACK_BIAS;
+ for (i = 0; i < 8; i++)
+ get_user_ual(env->regwptr[WREG_L0 + i], sp_ptr + i * 8);
+ for (i = 0; i < 6; i++) /* I0-I5; I6=FP and I7 already restored */
+ get_user_ual(env->regwptr[WREG_I0 + i], sp_ptr + 64 + i * 8);
+ }
+
fpup = &ucp->tuc_mcontext.mc_fpregs;
__get_user(fenab, &(fpup->mcfpu_enab));
--
2.54.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 06/10] linux-user/sparc: call block_signals() before set_sigmask() in setcontext
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
` (4 preceding siblings ...)
2026-06-07 14:03 ` [PATCH 05/10] linux-user/sparc: restore L/I registers from RSA in sparc64_set_context Helge Deller
@ 2026-06-07 14:03 ` Helge Deller
2026-06-07 14:03 ` [PATCH 07/10] linux-user/sparc: flush register windows before core dump Helge Deller
` (3 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller, Matt Turner, Mark Cave-Ayland
From: Matt Turner <mattst88@gmail.com>
sparc64_set_context() emulates the kernel's `ta 0x6f` trap by calling
set_sigmask() to install the mask supplied via the user's ucontext_t.
The contract of set_sigmask() (see its comment in linux-user/signal.c)
is that the caller must have first called block_signals(), which sets
TaskState::signal_pending.
Without block_signals(), if a guest signal is pending-and-blocked at
the time setcontext is invoked and the new mask unblocks it,
signal_pending stays 0 and the post-trap process_pending_signals()
call in linux-user/sparc/cpu_loop.c never enters its while loop, so
the now-deliverable signal is left undelivered indefinitely.
This affects programs that use getcontext/setcontext to swap signal
masks, including libunwind's unw_resume() out of a signal handler:
without this fix, the test program below loops forever printing
"calling setcontext" instead of delivering the pending SIGUSR2.
#define _GNU_SOURCE
#include <ucontext.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static int got;
static void h(int s) { got = 1; }
int main(void) {
signal(SIGUSR2, h);
sigset_t m; sigemptyset(&m); sigaddset(&m, SIGUSR2);
sigprocmask(SIG_BLOCK, &m, NULL);
kill(getpid(), SIGUSR2);
ucontext_t uc;
getcontext(&uc);
if (got) return 0;
uc.uc_sigmask.__val[0] = 0;
setcontext(&uc);
return 1;
}
The 32-bit sparc do_sigreturn / do_rt_sigreturn paths already get
block_signals() from the rt_sigreturn syscall wrapper in
linux-user/syscall.c, so only sparc64_set_context (invoked directly
from cpu_loop) needs the addition.
Signed-off-by: Matt Turner <mattst88@gmail.com>
Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Helge Deller <deller@gmx.de>
---
linux-user/sparc/signal.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
index fda5508c48..ba692c3123 100644
--- a/linux-user/sparc/signal.c
+++ b/linux-user/sparc/signal.c
@@ -619,6 +619,15 @@ void sparc64_set_context(CPUSPARCState *env)
}
}
target_to_host_sigset_internal(&set, &target_set);
+ /*
+ * set_sigmask() requires the caller to have first called
+ * block_signals() so that process_pending_signals() is guaranteed
+ * to run after the mask change. Without this, a guest signal that
+ * is pending-and-blocked at setcontext time is left undelivered
+ * even after its mask bit is cleared, because signal_pending stays
+ * 0 and the post-trap process_pending_signals() loop never enters.
+ */
+ block_signals();
set_sigmask(&set);
}
env->pc = pc;
--
2.54.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 07/10] linux-user/sparc: flush register windows before core dump
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
` (5 preceding siblings ...)
2026-06-07 14:03 ` [PATCH 06/10] linux-user/sparc: call block_signals() before set_sigmask() in setcontext Helge Deller
@ 2026-06-07 14:03 ` Helge Deller
2026-06-07 14:03 ` [PATCH 08/10] target/sh4: decode_gusa: recognize add#imm with prior mov Rm, Rn Helge Deller
` (2 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller, Matt Turner, Mark Cave-Ayland
From: Matt Turner <mattst88@gmail.com>
Without this, only the crash frame's window is spilled to the
stack; all deeper call frames remain in the register file and
are absent from the core's memory segments. Stack unwinding
fails past the first DWARF step because the callers' register
save areas contain stale/garbage data.
The real kernel calls flush_all_user_windows() at the top of
do_coredump(). Mirror that via a weak target_flush_windows()
hook called from dump_core_and_abort(), with the SPARC override
calling the existing flush_windows() in cpu_loop.c.
Signed-off-by: Matt Turner <mattst88@gmail.com>
Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Helge Deller <deller@gmx.de>
---
linux-user/elfload.c | 9 ++++++++
linux-user/sparc/cpu_loop.c | 3 ++-
linux-user/sparc/cpu_loop.h | 7 +++++++
linux-user/sparc/elfload.c | 39 +++++++++++++++++++++++++++++------
linux-user/sparc/target_elf.h | 17 +++++++++++----
5 files changed, 64 insertions(+), 11 deletions(-)
create mode 100644 linux-user/sparc/cpu_loop.h
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index f7625c0952..b05b8b0c6b 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -2445,6 +2445,9 @@ static int wmr_write_region(void *opaque, vaddr start,
* handler (provided that target process haven't registered
* handler for that) that does the dump when signal is received.
*/
+#ifdef TARGET_SPARC
+#include "sparc/cpu_loop.h"
+#endif
static int elf_core_dump(int signr, const CPUArchState *env)
{
const CPUState *cpu = env_cpu_const(env);
@@ -2468,6 +2471,12 @@ static int elf_core_dump(int signr, const CPUArchState *env)
cpu_list_lock();
mmap_lock();
+#ifdef TARGET_SPARC
+ CPU_FOREACH(cpu_iter) {
+ flush_windows(cpu_env(cpu_iter));
+ }
+#endif
+
/* By unprotecting, we merge vmas that might be split. */
walk_memory_regions(NULL, wmr_page_unprotect_regions);
diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c
index ab633eeae3..0aacda9448 100644
--- a/linux-user/sparc/cpu_loop.c
+++ b/linux-user/sparc/cpu_loop.c
@@ -22,6 +22,7 @@
#include "user-internals.h"
#include "user/cpu_loop.h"
#include "signal-common.h"
+#include "sparc/cpu_loop.h"
#define SPARC64_STACK_BIAS 2047
@@ -119,7 +120,7 @@ static void restore_window(CPUSPARCState *env)
#endif
}
-static void flush_windows(CPUSPARCState *env)
+void flush_windows(CPUSPARCState *env)
{
int offset, cwp1;
diff --git a/linux-user/sparc/cpu_loop.h b/linux-user/sparc/cpu_loop.h
new file mode 100644
index 0000000000..fb6e82d372
--- /dev/null
+++ b/linux-user/sparc/cpu_loop.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef SPARC_CPU_LOOP_H
+#define SPARC_CPU_LOOP_H
+
+void flush_windows(CPUSPARCState *env);
+
+#endif
diff --git a/linux-user/sparc/elfload.c b/linux-user/sparc/elfload.c
index e6387ec891..181f1e00b5 100644
--- a/linux-user/sparc/elfload.c
+++ b/linux-user/sparc/elfload.c
@@ -12,16 +12,41 @@ void elf_core_copy_regs(target_elf_gregset_t *r, const CPUArchState *env)
CPUSPARCState *e = (CPUSPARCState *)env;
int i;
+ memset(r, 0, sizeof(*r));
+
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ /* Linux kernel layout for sparc64 (arch/sparc/include/asm/elf_64.h):
+ * [0..7] G0-G7
+ * [8..15] O0-O7
+ * [16..23] L0-L7
+ * [24..31] I0-I7
+ * [32] TSTATE
+ * [33] TPC
+ * [34] TNPC
+ * [35] Y
+ */
for (i = 0; i < 8; i++) {
- r->regs[i] = tswap64(env->gregs[i]);
- r->regs[8 + i] = tswap64(env->regwptr[WREG_O0 + i]);
+ r->regs[i] = tswap64(env->gregs[i]);
+ r->regs[8 + i] = tswap64(env->regwptr[WREG_O0 + i]);
+ r->regs[16 + i] = tswap64(env->regwptr[WREG_L0 + i]);
+ r->regs[24 + i] = tswap64(env->regwptr[WREG_I0 + i]);
}
- r->regs[16] = tswap64(sparc64_tstate(e));
- r->regs[17] = tswap64(env->pc);
- r->regs[18] = tswap64(env->npc);
- r->regs[19] = tswap64(env->y);
+ r->regs[32] = tswap64(sparc64_tstate(e));
+ r->regs[33] = tswap64(env->pc);
+ r->regs[34] = tswap64(env->npc);
+ r->regs[35] = tswap64(env->y);
#else
+ /* Linux kernel layout for sparc32 (arch/sparc/include/asm/elf_32.h):
+ * [0] PSR
+ * [1] PC
+ * [2] NPC
+ * [3] Y
+ * [4..11] G0-G7
+ * [12..19] O0-O7
+ * [20..27] L0-L7
+ * [28..35] I0-I7
+ * [36..37] reserved (stack_check)
+ */
r->regs[0] = tswap32(cpu_get_psr(e));
r->regs[1] = tswap32(env->pc);
r->regs[2] = tswap32(env->npc);
@@ -29,6 +54,8 @@ void elf_core_copy_regs(target_elf_gregset_t *r, const CPUArchState *env)
for (i = 0; i < 8; i++) {
r->regs[4 + i] = tswap32(env->gregs[i]);
r->regs[12 + i] = tswap32(env->regwptr[WREG_O0 + i]);
+ r->regs[20 + i] = tswap32(env->regwptr[WREG_L0 + i]);
+ r->regs[28 + i] = tswap32(env->regwptr[WREG_I0 + i]);
}
#endif
}
diff --git a/linux-user/sparc/target_elf.h b/linux-user/sparc/target_elf.h
index edb0b3103c..365af864b0 100644
--- a/linux-user/sparc/target_elf.h
+++ b/linux-user/sparc/target_elf.h
@@ -24,12 +24,21 @@
#define HAVE_ELF_CORE_DUMP 1
/*
- * Matches the kernel's elf_gregset_t (ELF_NGREG = 20).
- * sparc32/sparc32plus: psr, pc, npc, y, u_regs[16] (g0-g7, o0-o7)
- * sparc64: u_regs[16] (g0-g7, o0-o7), tstate, pc, npc, y
+ * Matches the kernel's elf_gregset_t.
+ * sparc32/sparc32plus (ELF_NGREG = 38):
+ * psr, pc, npc, y, u_regs[16] (g0-g7, o0-o7),
+ * reg_window[16] (l0-l7, i0-i7), stack_check[2]
+ * sparc64 (ELF_NGREG = 36):
+ * u_regs[16] (g0-g7, o0-o7), reg_window[16] (l0-l7, i0-i7),
+ * tstate, tpc, tnpc, y
*/
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+# define TARGET_ELF_NGREG 36
+#else
+# define TARGET_ELF_NGREG 38
+#endif
typedef struct target_elf_gregset_t {
- abi_ulong regs[20];
+ abi_ulong regs[TARGET_ELF_NGREG];
} target_elf_gregset_t;
#endif
--
2.54.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 08/10] target/sh4: decode_gusa: recognize add#imm with prior mov Rm, Rn
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
` (6 preceding siblings ...)
2026-06-07 14:03 ` [PATCH 07/10] linux-user/sparc: flush register windows before core dump Helge Deller
@ 2026-06-07 14:03 ` Helge Deller
2026-06-07 14:03 ` [PATCH 09/10] linux-user/xtensa: restore FP rounding mode on sigreturn Helge Deller
2026-06-07 14:03 ` [PATCH 10/10] target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status Helge Deller
9 siblings, 0 replies; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller, Matt Turner, Richard Henderson
From: Matt Turner <mattst88@gmail.com>
The gUSA pattern matcher rejected `add #imm, Rn` whenever any prior
`mov Rm, Rn` appeared (mv_src >= 0), forcing a fallback to
cpu_exec_step_atomic for sequences like:
mov.l @r2, r3 ; load
mov r3, r7 ; save old value (mv_src == ld_dst)
add #1, r7 ; increment copy
mov.l r7, @r2 ; store
When mv_src == ld_dst the move merely copies the loaded value to
preserve it -- exactly the situation already accepted for the
`add Rm, Rn` form. The immediate form can be handled identically with
tcg_gen_atomic_fetch_add_i32 + tcg_gen_add_i32, so translate it inline
instead of taking the slower single-step atomic fallback.
Signed-off-by: Matt Turner <mattst88@gmail.com>
Cc: Yoshinori Sato <yoshinori.sato@nifty.com>
Cc: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Helge Deller <deller@gmx.de>
---
target/sh4/translate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index 5adf650744..d38a6bd352 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -1974,7 +1974,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env)
break;
case 0x7000 ... 0x700f: /* add #imm,Rn */
- if (op_dst != B11_8 || mv_src >= 0) {
+ if (op_dst != B11_8 || (mv_src >= 0 && mv_src != ld_dst)) {
goto fail;
}
op_opc = INDEX_op_add;
--
2.54.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 09/10] linux-user/xtensa: restore FP rounding mode on sigreturn
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
` (7 preceding siblings ...)
2026-06-07 14:03 ` [PATCH 08/10] target/sh4: decode_gusa: recognize add#imm with prior mov Rm, Rn Helge Deller
@ 2026-06-07 14:03 ` Helge Deller
2026-06-07 20:06 ` Max Filippov
2026-06-07 14:03 ` [PATCH 10/10] target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status Helge Deller
9 siblings, 1 reply; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller, Matt Turner
From: Matt Turner <mattst88@gmail.com>
The Xtensa FCR rounding-mode (RM) bits are not held only in
env->uregs[FCR]: they are also reflected into env->fp_status via
set_float_rounding_mode(). Similarly, FSR exception flags are mirrored
into env->fp_status. Every write to FCR/FSR goes through
helper_wur_fpu{2k,}_fcr / helper_wur_fpu_fsr which keep the two in sync.
restore_sigcontext() previously wrote nothing back for xtregs, leaving
env->fp_status with whatever rounding mode and exception flags the
signal handler last installed. Any FP instruction in the interrupted
code could then operate with the wrong mode.
Add a minimal target_xtensa_xtregs sub-frame carrying FCR and FSR.
setup_sigcontext() saves the current values and points sc_xtregs at the
sub-frame when XTENSA_OPTION_FP_COPROCESSOR or
XTENSA_OPTION_DFP_COPROCESSOR is present (both use env->fp_status driven
by FCR/FSR). restore_sigcontext() reads sc_xtregs; if non-zero it
restores FCR and FSR through cpu_set_fcr()/cpu_set_fsr() so fp_status
round-trips correctly across signal delivery.
Signed-off-by: Matt Turner <mattst88@gmail.com>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Helge Deller <deller@gmx.de>
---
linux-user/xtensa/signal.c | 36 +++++++++++++++++++++++++++++++-----
1 file changed, 31 insertions(+), 5 deletions(-)
diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
index ef8b0c3a27..fef23952b7 100644
--- a/linux-user/xtensa/signal.c
+++ b/linux-user/xtensa/signal.c
@@ -21,6 +21,7 @@
#include "user-internals.h"
#include "signal-common.h"
#include "linux-user/trace.h"
+#include "target/xtensa/cpu.h"
struct target_sigcontext {
abi_ulong sc_pc;
@@ -43,10 +44,15 @@ struct target_ucontext {
target_sigset_t tuc_sigmask;
};
+struct target_xtensa_xtregs {
+ uint32_t fcr;
+ uint32_t fsr;
+};
+
struct target_rt_sigframe {
target_siginfo_t info;
struct target_ucontext uc;
- /* TODO: xtregs */
+ struct target_xtensa_xtregs xtregs;
uint8_t retcode[6];
abi_ulong window[4];
};
@@ -107,6 +113,7 @@ static int flush_window_regs(CPUXtensaState *env)
}
static int setup_sigcontext(struct target_rt_sigframe *frame,
+ abi_ulong frame_addr,
CPUXtensaState *env)
{
struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
@@ -123,8 +130,15 @@ static int setup_sigcontext(struct target_rt_sigframe *frame,
for (i = 0; i < 16; ++i) {
__put_user(env->regs[i], sc->sc_a + i);
}
- __put_user(0, &sc->sc_xtregs);
- /* TODO: xtregs */
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_FP_COPROCESSOR) ||
+ xtensa_option_enabled(env->config, XTENSA_OPTION_DFP_COPROCESSOR)) {
+ __put_user(env->uregs[FCR], &frame->xtregs.fcr);
+ __put_user(cpu_get_fsr(env), &frame->xtregs.fsr);
+ __put_user(frame_addr + offsetof(struct target_rt_sigframe, xtregs),
+ &sc->sc_xtregs);
+ } else {
+ __put_user(0, &sc->sc_xtregs);
+ }
return 1;
}
@@ -190,7 +204,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
__put_user(0, &frame->uc.tuc_flags);
__put_user(0, &frame->uc.tuc_link);
target_save_altstack(&frame->uc.tuc_stack, env);
- if (!setup_sigcontext(frame, env)) {
+ if (!setup_sigcontext(frame, frame_addr, env)) {
unlock_user_struct(frame, frame_addr, 0);
goto give_sigsegv;
}
@@ -266,7 +280,19 @@ static void restore_sigcontext(CPUXtensaState *env,
for (i = 0; i < 16; ++i) {
__get_user(env->regs[i], sc->sc_a + i);
}
- /* TODO: xtregs */
+ {
+ abi_ulong xtregs_addr;
+
+ __get_user(xtregs_addr, &sc->sc_xtregs);
+ if (xtregs_addr) {
+ uint32_t fcr, fsr;
+
+ __get_user(fcr, &frame->xtregs.fcr);
+ __get_user(fsr, &frame->xtregs.fsr);
+ cpu_set_fcr(env, fcr);
+ cpu_set_fsr(env, fsr);
+ }
+ }
}
long do_rt_sigreturn(CPUXtensaState *env)
--
2.54.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 10/10] target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
` (8 preceding siblings ...)
2026-06-07 14:03 ` [PATCH 09/10] linux-user/xtensa: restore FP rounding mode on sigreturn Helge Deller
@ 2026-06-07 14:03 ` Helge Deller
2026-06-07 20:26 ` Max Filippov
9 siblings, 1 reply; 15+ messages in thread
From: Helge Deller @ 2026-06-07 14:03 UTC (permalink / raw)
To: qemu-devel
Cc: Pierrick Bouvier, Laurent Vivier, Yoshinori Sato, Max Filippov,
Helge Deller, Matt Turner
From: Matt Turner <mattst88@gmail.com>
Factor FCR→fp_status and FSR→fp_status synchronisation out of the
wur_fpu{2k,}_fcr/wur_fpu_fsr helpers into cpu_set_fcr(), cpu_set_fsr(),
and cpu_get_fsr(). Signal delivery code needs to restore the FP rounding
mode and exception flags without duplicating the flag-mapping tables.
cpu_set_fcr() applies the union mask 0xfffff07f (superset of the
wur_fpu_fcr mask 0x0000007f and the wur_fpu2k_fcr mask 0xfffff07f) so
that FCR bits valid only on fpu2k configs are preserved while MBZ bits
7-11 are always cleared.
v2: Use FloatRoundMode as suggested by Richard.
Signed-off-by: Matt Turner <mattst88@gmail.com>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Helge Deller <deller@gmx.de>
---
target/xtensa/cpu.h | 4 ++++
target/xtensa/fpu_helper.c | 42 ++++++++++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index 75cfeee6e3..442e98bd1b 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -642,6 +642,10 @@ static inline void xtensa_select_static_vectors(CPUXtensaState *env,
}
void xtensa_runstall(CPUXtensaState *env, bool runstall);
+uint32_t cpu_get_fsr(CPUXtensaState *env);
+void cpu_set_fcr(CPUXtensaState *env, uint32_t v);
+void cpu_set_fsr(CPUXtensaState *env, uint32_t v);
+
#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
#define XTENSA_OPTION_ALL (~(uint64_t)0)
diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c
index 5358060c50..9f1256f677 100644
--- a/target/xtensa/fpu_helper.c
+++ b/target/xtensa/fpu_helper.c
@@ -64,6 +64,48 @@ void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
&env->fp_status);
}
+uint32_t cpu_get_fsr(CPUXtensaState *env)
+{
+ uint32_t flags = 0;
+ int fef = get_float_exception_flags(&env->fp_status);
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
+ if (fef & xtensa_fp_flag_map[i].softfloat_fp_flag) {
+ flags |= xtensa_fp_flag_map[i].xtensa_fp_flag;
+ }
+ }
+ return flags << XTENSA_FSR_FLAGS_SHIFT;
+}
+
+void cpu_set_fcr(CPUXtensaState *env, uint32_t v)
+{
+ static const FloatRoundMode rounding_mode[] = {
+ float_round_nearest_even,
+ float_round_to_zero,
+ float_round_up,
+ float_round_down,
+ };
+
+ env->uregs[FCR] = v & 0xfffff07f;
+ set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
+}
+
+void cpu_set_fsr(CPUXtensaState *env, uint32_t v)
+{
+ uint32_t flags = v >> XTENSA_FSR_FLAGS_SHIFT;
+ int fef = 0;
+ unsigned i;
+
+ env->uregs[FSR] = v & 0x00000f80;
+ for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
+ if (flags & xtensa_fp_flag_map[i].xtensa_fp_flag) {
+ fef |= xtensa_fp_flag_map[i].softfloat_fp_flag;
+ }
+ }
+ set_float_exception_flags(fef, &env->fp_status);
+}
+
void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
{
static const int rounding_mode[] = {
--
2.54.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 03/10] linux-user/alpha: add coredump support
2026-06-07 14:03 ` [PATCH 03/10] linux-user/alpha: add coredump support Helge Deller
@ 2026-06-07 15:30 ` Richard Henderson
0 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2026-06-07 15:30 UTC (permalink / raw)
To: qemu-devel
On 6/7/26 07:03, Helge Deller wrote:
> From: Matt Turner <mattst88@gmail.com>
>
> Define HAVE_ELF_CORE_DUMP and target_elf_gregset_t in target_elf.h,
> mirroring the kernel's elf_gregset_t (ELF_NGREG = 66): r0-r31
> [0..31], f0-f31 [32..63], pc [64], unique [65]. Implement
> elf_core_copy_regs() in elfload.c to populate the gregset from
> CPUAlphaState.
>
> Without this, bprm->core_dump is NULL for Alpha targets. When a
> guest signal goes unhandled, dump_core_and_abort() skips the core
> write and falls through to die_with_signal(), which re-raises the
> signal to the host. The host kernel then writes an x86-64 core file
> for the qemu-alpha process instead of an Alpha guest core.
>
> v2: Store thread unique field, same as in Linux kernel. Added by Helge &
> suggested by Richard.
>
> Signed-off-by: Matt Turner <mattst88@gmail.com>
> Signed-off-by: Helge Deller <deller@gmx.de>
> ---
> linux-user/alpha/elfload.c | 12 ++++++++++++
> linux-user/alpha/target_elf.h | 13 +++++++++++++
> 2 files changed, 25 insertions(+)
>
> diff --git a/linux-user/alpha/elfload.c b/linux-user/alpha/elfload.c
> index 1e44475c47..d2aed15ce5 100644
> --- a/linux-user/alpha/elfload.c
> +++ b/linux-user/alpha/elfload.c
> @@ -3,8 +3,20 @@
> #include "qemu/osdep.h"
> #include "qemu.h"
> #include "loader.h"
> +#include "target_elf.h"
>
>
> +void elf_core_copy_regs(target_elf_gregset_t *r, const CPUAlphaState *env)
> +{
> + int i;
> +
> + for (i = 0; i < 31; i++) {
> + r->regs[i] = tswap64(env->ir[i]);
> + }
> + r->pc = tswap64(env->pc);
> + r->unique = env->unique;
Swap required. Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 09/10] linux-user/xtensa: restore FP rounding mode on sigreturn
2026-06-07 14:03 ` [PATCH 09/10] linux-user/xtensa: restore FP rounding mode on sigreturn Helge Deller
@ 2026-06-07 20:06 ` Max Filippov
2026-06-08 19:38 ` Helge Deller
0 siblings, 1 reply; 15+ messages in thread
From: Max Filippov @ 2026-06-07 20:06 UTC (permalink / raw)
To: Helge Deller
Cc: qemu-devel, Pierrick Bouvier, Laurent Vivier, Yoshinori Sato,
Helge Deller, Matt Turner
On Sun, Jun 7, 2026 at 7:04 AM Helge Deller <deller@kernel.org> wrote:
>
> From: Matt Turner <mattst88@gmail.com>
>
> The Xtensa FCR rounding-mode (RM) bits are not held only in
> env->uregs[FCR]: they are also reflected into env->fp_status via
> set_float_rounding_mode(). Similarly, FSR exception flags are mirrored
> into env->fp_status. Every write to FCR/FSR goes through
> helper_wur_fpu{2k,}_fcr / helper_wur_fpu_fsr which keep the two in sync.
>
> restore_sigcontext() previously wrote nothing back for xtregs, leaving
> env->fp_status with whatever rounding mode and exception flags the
> signal handler last installed. Any FP instruction in the interrupted
> code could then operate with the wrong mode.
>
> Add a minimal target_xtensa_xtregs sub-frame carrying FCR and FSR.
The structure of the xtregs area is defined by the target xtensa core and
this definition doesn't match what a typical core with FPU would produce.
Also this area saves not only FCR and FSR, but all of the FPU registers,
which are caller-saved. Not saving them means that any operation
that touches FPU registers in the signal handler context will clobber
them for the code that was interrupted by the signal.
> setup_sigcontext() saves the current values and points sc_xtregs at the
> sub-frame when XTENSA_OPTION_FP_COPROCESSOR or
> XTENSA_OPTION_DFP_COPROCESSOR is present (both use env->fp_status driven
> by FCR/FSR). restore_sigcontext() reads sc_xtregs; if non-zero it
> restores FCR and FSR through cpu_set_fcr()/cpu_set_fsr() so fp_status
> round-trips correctly across signal delivery.
>
> Signed-off-by: Matt Turner <mattst88@gmail.com>
> Cc: Max Filippov <jcmvbkbc@gmail.com>
> Signed-off-by: Helge Deller <deller@gmx.de>
> ---
> linux-user/xtensa/signal.c | 36 +++++++++++++++++++++++++++++++-----
> 1 file changed, 31 insertions(+), 5 deletions(-)
>
> diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
> index ef8b0c3a27..fef23952b7 100644
> --- a/linux-user/xtensa/signal.c
> +++ b/linux-user/xtensa/signal.c
> @@ -21,6 +21,7 @@
> #include "user-internals.h"
> #include "signal-common.h"
> #include "linux-user/trace.h"
> +#include "target/xtensa/cpu.h"
>
> struct target_sigcontext {
> abi_ulong sc_pc;
> @@ -43,10 +44,15 @@ struct target_ucontext {
> target_sigset_t tuc_sigmask;
> };
>
> +struct target_xtensa_xtregs {
> + uint32_t fcr;
> + uint32_t fsr;
> +};
> +
> struct target_rt_sigframe {
> target_siginfo_t info;
> struct target_ucontext uc;
> - /* TODO: xtregs */
> + struct target_xtensa_xtregs xtregs;
> uint8_t retcode[6];
> abi_ulong window[4];
> };
> @@ -107,6 +113,7 @@ static int flush_window_regs(CPUXtensaState *env)
> }
>
> static int setup_sigcontext(struct target_rt_sigframe *frame,
> + abi_ulong frame_addr,
> CPUXtensaState *env)
> {
> struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
> @@ -123,8 +130,15 @@ static int setup_sigcontext(struct target_rt_sigframe *frame,
> for (i = 0; i < 16; ++i) {
> __put_user(env->regs[i], sc->sc_a + i);
> }
> - __put_user(0, &sc->sc_xtregs);
> - /* TODO: xtregs */
> + if (xtensa_option_enabled(env->config, XTENSA_OPTION_FP_COPROCESSOR) ||
> + xtensa_option_enabled(env->config, XTENSA_OPTION_DFP_COPROCESSOR)) {
> + __put_user(env->uregs[FCR], &frame->xtregs.fcr);
> + __put_user(cpu_get_fsr(env), &frame->xtregs.fsr);
cpu_get_fsr() is introduced in the next patch of the series. It should go before
this one to keep the series bisectable.
> + __put_user(frame_addr + offsetof(struct target_rt_sigframe, xtregs),
> + &sc->sc_xtregs);
> + } else {
> + __put_user(0, &sc->sc_xtregs);
> + }
> return 1;
> }
>
> @@ -190,7 +204,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> __put_user(0, &frame->uc.tuc_flags);
> __put_user(0, &frame->uc.tuc_link);
> target_save_altstack(&frame->uc.tuc_stack, env);
> - if (!setup_sigcontext(frame, env)) {
> + if (!setup_sigcontext(frame, frame_addr, env)) {
> unlock_user_struct(frame, frame_addr, 0);
> goto give_sigsegv;
> }
> @@ -266,7 +280,19 @@ static void restore_sigcontext(CPUXtensaState *env,
> for (i = 0; i < 16; ++i) {
> __get_user(env->regs[i], sc->sc_a + i);
> }
> - /* TODO: xtregs */
> + {
> + abi_ulong xtregs_addr;
> +
> + __get_user(xtregs_addr, &sc->sc_xtregs);
> + if (xtregs_addr) {
> + uint32_t fcr, fsr;
> +
> + __get_user(fcr, &frame->xtregs.fcr);
> + __get_user(fsr, &frame->xtregs.fsr);
> + cpu_set_fcr(env, fcr);
> + cpu_set_fsr(env, fsr);
Same here.
--
Thanks.
-- Max
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 10/10] target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status
2026-06-07 14:03 ` [PATCH 10/10] target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status Helge Deller
@ 2026-06-07 20:26 ` Max Filippov
0 siblings, 0 replies; 15+ messages in thread
From: Max Filippov @ 2026-06-07 20:26 UTC (permalink / raw)
To: Helge Deller
Cc: qemu-devel, Pierrick Bouvier, Laurent Vivier, Yoshinori Sato,
Helge Deller, Matt Turner
On Sun, Jun 7, 2026 at 7:04 AM Helge Deller <deller@kernel.org> wrote:
>
> From: Matt Turner <mattst88@gmail.com>
>
> Factor FCR→fp_status and FSR→fp_status synchronisation out of the
> wur_fpu{2k,}_fcr/wur_fpu_fsr helpers into cpu_set_fcr(), cpu_set_fsr(),
> and cpu_get_fsr(). Signal delivery code needs to restore the FP rounding
> mode and exception flags without duplicating the flag-mapping tables.
>
> cpu_set_fcr() applies the union mask 0xfffff07f (superset of the
> wur_fpu_fcr mask 0x0000007f and the wur_fpu2k_fcr mask 0xfffff07f) so
> that FCR bits valid only on fpu2k configs are preserved while MBZ bits
> 7-11 are always cleared.
>
> v2: Use FloatRoundMode as suggested by Richard.
>
> Signed-off-by: Matt Turner <mattst88@gmail.com>
> Cc: Max Filippov <jcmvbkbc@gmail.com>
> Signed-off-by: Helge Deller <deller@gmx.de>
> ---
> target/xtensa/cpu.h | 4 ++++
> target/xtensa/fpu_helper.c | 42 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 46 insertions(+)
>
> diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
> index 75cfeee6e3..442e98bd1b 100644
> --- a/target/xtensa/cpu.h
> +++ b/target/xtensa/cpu.h
> @@ -642,6 +642,10 @@ static inline void xtensa_select_static_vectors(CPUXtensaState *env,
> }
> void xtensa_runstall(CPUXtensaState *env, bool runstall);
>
> +uint32_t cpu_get_fsr(CPUXtensaState *env);
> +void cpu_set_fcr(CPUXtensaState *env, uint32_t v);
> +void cpu_set_fsr(CPUXtensaState *env, uint32_t v);
> +
> #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
> #define XTENSA_OPTION_ALL (~(uint64_t)0)
>
> diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c
> index 5358060c50..9f1256f677 100644
> --- a/target/xtensa/fpu_helper.c
> +++ b/target/xtensa/fpu_helper.c
> @@ -64,6 +64,48 @@ void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
> &env->fp_status);
> }
>
> +uint32_t cpu_get_fsr(CPUXtensaState *env)
> +{
> + uint32_t flags = 0;
> + int fef = get_float_exception_flags(&env->fp_status);
> + unsigned i;
> +
> + for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
> + if (fef & xtensa_fp_flag_map[i].softfloat_fp_flag) {
> + flags |= xtensa_fp_flag_map[i].xtensa_fp_flag;
> + }
> + }
> + return flags << XTENSA_FSR_FLAGS_SHIFT;
> +}
rur_fpu_fsr() could be reimplemented using this function.
> +void cpu_set_fcr(CPUXtensaState *env, uint32_t v)
> +{
> + static const FloatRoundMode rounding_mode[] = {
> + float_round_nearest_even,
> + float_round_to_zero,
> + float_round_up,
> + float_round_down,
> + };
> +
> + env->uregs[FCR] = v & 0xfffff07f;
> + set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
> +}
Both wur_fpu2k_fcr() and wur_fpu_fcr() could be reimplemented
using this function.
> +
> +void cpu_set_fsr(CPUXtensaState *env, uint32_t v)
> +{
> + uint32_t flags = v >> XTENSA_FSR_FLAGS_SHIFT;
> + int fef = 0;
> + unsigned i;
> +
> + env->uregs[FSR] = v & 0x00000f80;
> + for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
> + if (flags & xtensa_fp_flag_map[i].xtensa_fp_flag) {
> + fef |= xtensa_fp_flag_map[i].softfloat_fp_flag;
> + }
> + }
> + set_float_exception_flags(fef, &env->fp_status);
> +}
wur_fpu_fsr() could be reimplemented using this function.
> void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
> {
> static const int rounding_mode[] = {
> --
> 2.54.0
>
--
Thanks.
-- Max
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 09/10] linux-user/xtensa: restore FP rounding mode on sigreturn
2026-06-07 20:06 ` Max Filippov
@ 2026-06-08 19:38 ` Helge Deller
0 siblings, 0 replies; 15+ messages in thread
From: Helge Deller @ 2026-06-08 19:38 UTC (permalink / raw)
To: Max Filippov, Matt Turner
Cc: qemu-devel, Pierrick Bouvier, Laurent Vivier, Yoshinori Sato
On 6/7/26 22:06, Max Filippov wrote:
> On Sun, Jun 7, 2026 at 7:04 AM Helge Deller <deller@kernel.org> wrote:
>>
>> From: Matt Turner <mattst88@gmail.com>
>>
>> The Xtensa FCR rounding-mode (RM) bits are not held only in
>> env->uregs[FCR]: they are also reflected into env->fp_status via
>> set_float_rounding_mode(). Similarly, FSR exception flags are mirrored
>> into env->fp_status. Every write to FCR/FSR goes through
>> helper_wur_fpu{2k,}_fcr / helper_wur_fpu_fsr which keep the two in sync.
>>
>> restore_sigcontext() previously wrote nothing back for xtregs, leaving
>> env->fp_status with whatever rounding mode and exception flags the
>> signal handler last installed. Any FP instruction in the interrupted
>> code could then operate with the wrong mode.
>>
>> Add a minimal target_xtensa_xtregs sub-frame carrying FCR and FSR.
>
> The structure of the xtregs area is defined by the target xtensa core and
> this definition doesn't match what a typical core with FPU would produce.
>
> Also this area saves not only FCR and FSR, but all of the FPU registers,
> which are caller-saved. Not saving them means that any operation
> that touches FPU registers in the signal handler context will clobber
> them for the code that was interrupted by the signal.
I see this patch and the next one ("target/xtensa: add cpu_set_fcr/fsr
helpers to sync fp_status") need some more cleanups.
I'll drop them for now from this series.
They can go in later after fixing by another pull series or through a xtensa tree...
Helge
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-06-08 19:39 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-07 14:03 [PATCH 00/10] linux-user patches for alpha, sparc, sh4 and xtensa Helge Deller
2026-06-07 14:03 ` [PATCH 01/10] linux-user: implement fsmount(2) series of syscalls Helge Deller
2026-06-07 14:03 ` [PATCH 02/10] linux-user/strace: add fsmount " Helge Deller
2026-06-07 14:03 ` [PATCH 03/10] linux-user/alpha: add coredump support Helge Deller
2026-06-07 15:30 ` Richard Henderson
2026-06-07 14:03 ` [PATCH 04/10] linux-user/sparc: " Helge Deller
2026-06-07 14:03 ` [PATCH 05/10] linux-user/sparc: restore L/I registers from RSA in sparc64_set_context Helge Deller
2026-06-07 14:03 ` [PATCH 06/10] linux-user/sparc: call block_signals() before set_sigmask() in setcontext Helge Deller
2026-06-07 14:03 ` [PATCH 07/10] linux-user/sparc: flush register windows before core dump Helge Deller
2026-06-07 14:03 ` [PATCH 08/10] target/sh4: decode_gusa: recognize add#imm with prior mov Rm, Rn Helge Deller
2026-06-07 14:03 ` [PATCH 09/10] linux-user/xtensa: restore FP rounding mode on sigreturn Helge Deller
2026-06-07 20:06 ` Max Filippov
2026-06-08 19:38 ` Helge Deller
2026-06-07 14:03 ` [PATCH 10/10] target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status Helge Deller
2026-06-07 20:26 ` Max Filippov
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.