All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 0/4] Linux user patches
@ 2026-06-12 15:50 Helge Deller
  2026-06-12 15:50 ` [PULL 1/4] linux-user: add preadv2/preadv2 Helge Deller
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Helge Deller @ 2026-06-12 15:50 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel
  Cc: Helge Deller, Pierrick Bouvier, Laurent Vivier, Max Filippov

From: Helge Deller <deller@gmx.de>

The following changes since commit ec6a1f43989c6bbf2de1ab84959a70ee35fa1b57:

  Merge tag 'linux-user-pull-request' of https://github.com/hdeller/qemu-hppa into staging (2026-06-11 13:22:50 -0400)

are available in the Git repository at:

  https://github.com/hdeller/qemu-hppa.git tags/linux-user-pull-request

for you to fetch changes up to 6858e3a71cc41510937bec0950eb4e42e33ba5f2:

  linux-user/xtensa: save/restore FP registers across signal delivery (2026-06-12 17:47:27 +0200)

----------------------------------------------------------------
linux-user patches

Add preadv2/preadv2 syscalls, fix FP registers across signals on xtensa, and
add emulation for /proc/cpuinfo for ppc CPUs

----------------------------------------------------------------

Dominique Martinet (1):
  linux-user: add preadv2/preadv2

Helge Deller (1):
  linux-user: Implement /proc/cpuinfo for ppc cpus

Matt Turner (2):
  target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status
  linux-user/xtensa: save/restore FP registers across signal delivery

 linux-user/ppc/cpu_loop.c    |  2 +-
 linux-user/ppc/target_proc.h | 91 +++++++++++++++++++++++++++++++++-
 linux-user/syscall.c         | 38 ++++++++++++++
 linux-user/xtensa/signal.c   | 96 +++++++++++++++++++++++++++++++++---
 target/xtensa/cpu.h          |  4 ++
 target/xtensa/fpu_helper.c   | 71 ++++++++++++++------------
 6 files changed, 261 insertions(+), 41 deletions(-)

-- 
2.54.0



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PULL 1/4] linux-user: add preadv2/preadv2
  2026-06-12 15:50 [PULL 0/4] Linux user patches Helge Deller
@ 2026-06-12 15:50 ` Helge Deller
  2026-06-12 15:50 ` [PULL 2/4] linux-user: Implement /proc/cpuinfo for ppc cpus Helge Deller
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Helge Deller @ 2026-06-12 15:50 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel
  Cc: Helge Deller, Pierrick Bouvier, Laurent Vivier, Max Filippov,
	Dominique Martinet

From: Dominique Martinet <dominique.martinet@atmark-techno.com>

Some programs apparently use these, like the python test suite.

The flags argument (rwf_t) is an int, with values shared on all arches
and does not need translating.

This was tested manually with the following python script:
```
import os
fd = os.open('test', os.O_RDWR|os.O_CREAT)
os.pwritev(fd, [b'test', b'ok'], 0, os.RWF_HIPRI)
buf = [bytearray(3), bytearray(10)]
os.preadv(fd, buf, 0, os.RWF_HIPRI)
print(buf[0])
print(buf[1])
```

Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
Reviewed-by: Helge Deller <deller@gmx.de>
Signed-off-by: Helge Deller <deller@gmx.de>
---
 linux-user/syscall.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 37ede95510..fbe357b7e0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -741,6 +741,11 @@ safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
               unsigned long, pos_l, unsigned long, pos_h)
 safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
               unsigned long, pos_l, unsigned long, pos_h)
+safe_syscall6(ssize_t, preadv2, int, fd, const struct iovec *, iov, int, iovcnt,
+              unsigned long, pos_l, unsigned long, pos_h, __kernel_rwf_t, flags)
+safe_syscall6(ssize_t, pwritev2, int, fd, const struct iovec *, iov,
+              int, iovcnt, unsigned long, pos_l, unsigned long, pos_h,
+              __kernel_rwf_t, flags)
 safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr,
               socklen_t, addrlen)
 safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len,
@@ -11907,6 +11912,39 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
            }
         }
         return ret;
+#endif
+#if defined(TARGET_NR_preadv2)
+    case TARGET_NR_preadv2:
+        {
+            struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
+            if (vec != NULL) {
+                unsigned long low, high;
+
+                target_to_host_low_high(arg4, arg5, &low, &high);
+                ret = get_errno(safe_preadv2(arg1, vec, arg3, low, high, arg6));
+                unlock_iovec(vec, arg2, arg3, 1);
+            } else {
+                ret = -host_to_target_errno(errno);
+           }
+        }
+        return ret;
+#endif
+#if defined(TARGET_NR_pwritev2)
+    case TARGET_NR_pwritev2:
+        {
+            struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
+            if (vec != NULL) {
+                unsigned long low, high;
+
+                target_to_host_low_high(arg4, arg5, &low, &high);
+                ret = get_errno(safe_pwritev2(arg1, vec, arg3, low, high,
+                                              arg6));
+                unlock_iovec(vec, arg2, arg3, 0);
+            } else {
+                ret = -host_to_target_errno(errno);
+           }
+        }
+        return ret;
 #endif
     case TARGET_NR_getsid:
         return get_errno(getsid(arg1));
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PULL 2/4] linux-user: Implement /proc/cpuinfo for ppc cpus
  2026-06-12 15:50 [PULL 0/4] Linux user patches Helge Deller
  2026-06-12 15:50 ` [PULL 1/4] linux-user: add preadv2/preadv2 Helge Deller
@ 2026-06-12 15:50 ` Helge Deller
  2026-06-12 15:50 ` [PULL 3/4] target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status Helge Deller
  2026-06-12 15:50 ` [PULL 4/4] linux-user/xtensa: save/restore FP registers across signal delivery Helge Deller
  3 siblings, 0 replies; 5+ messages in thread
From: Helge Deller @ 2026-06-12 15:50 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel
  Cc: Helge Deller, Pierrick Bouvier, Laurent Vivier, Max Filippov,
	Richard Henderson

From: Helge Deller <deller@gmx.de>

Mimic the entries for /proc/cpuinfo to what can be seen on two debian
porterboxes (ppc64 and ppc64le), which are running via KVM/QEMU.

The "timebase" value in /proc/cpuinfo is used by glibc on power, but only if
the __kernel_get_tbfreq vdso call isn't implemented. So switch
cpu_ppc_load_tbl() for linux-user to get_clock(), as suggested by Richard, and
report timebase = 1GHz in /proc/cpuinfo, which will make the vdso
implementation simple too.

v4: change timebase to 1GHz and use get_clock()
v3: drop another colon, indenting fixes
v2: drop colon, add clock output, refine pvr calculation

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Helge Deller <deller@gmx.de>
---
 linux-user/ppc/cpu_loop.c    |  2 +-
 linux-user/ppc/target_proc.h | 91 +++++++++++++++++++++++++++++++++++-
 2 files changed, 91 insertions(+), 2 deletions(-)

diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
index 1f9ee20bd0..7c53e25a93 100644
--- a/linux-user/ppc/cpu_loop.c
+++ b/linux-user/ppc/cpu_loop.c
@@ -26,7 +26,7 @@
 
 static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
 {
-    return cpu_get_host_ticks();
+    return get_clock();
 }
 
 uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
diff --git a/linux-user/ppc/target_proc.h b/linux-user/ppc/target_proc.h
index 43fe29ca72..0a48fd65e9 100644
--- a/linux-user/ppc/target_proc.h
+++ b/linux-user/ppc/target_proc.h
@@ -1 +1,90 @@
-/* No target-specific /proc support */
+/*
+ * ppc specific proc functions for linux-user
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef PPC_TARGET_PROC_H
+#define PPC_TARGET_PROC_H
+
+#include <time.h>
+
+#define PVR_VER(pvr)    (((pvr) >>  16) & 0xFFFF)      /* Version field */
+#define PVR_REV(pvr)    (((pvr) >>   0) & 0xFFFF)      /* Revison field */
+#define PVR_MAJ(pvr)    (((pvr) >>  4) & 0xF)   /* Major revision field */
+#define PVR_MIN(pvr)    (((pvr) >>  0) & 0xF)   /* Minor revision field */
+
+static int open_cpuinfo(CPUArchState *cpu_env, int fd)
+{
+    struct timespec res;
+    double freq_mhz;
+    int i, num_cpus;
+    unsigned int maj, min, pvr;
+
+    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(env_cpu(cpu_env));
+    DeviceClass *dc = DEVICE_CLASS(ppc_cpu_get_family_class(pcc));
+
+    pvr = pcc->pvr;
+
+    /* Taken from Linux kernel: */
+    /* If we are a Freescale core do a simple check so
+     * we don't have to keep adding cases in the future */
+    if (PVR_VER(pvr) & 0x8000) {
+        switch (PVR_VER(pvr)) {
+        case 0x8000: /* 7441/7450/7451, Voyager */
+        case 0x8001: /* 7445/7455, Apollo 6 */
+        case 0x8002: /* 7447/7457, Apollo 7 */
+        case 0x8003: /* 7447A, Apollo 7 PM */
+        case 0x8004: /* 7448, Apollo 8 */
+        case 0x800c: /* 7410, Nitro */
+            maj = ((pvr >> 8) & 0xF);
+            min = PVR_MIN(pvr);
+            break;
+        default:     /* e500/book-e */
+            maj = PVR_MAJ(pvr);
+            min = PVR_MIN(pvr);
+            break;
+        }
+    } else {
+        switch (PVR_VER(pvr)) {
+        case 0x1008: /* 740P/750P ?? */
+            maj = ((pvr >> 8) & 0xFF) - 1;
+            min = pvr & 0xFF;
+            break;
+        case 0x004e: /* POWER9 bits 12-15 give chip type */
+        case 0x0080: /* POWER10 bit 12 gives SMT8/4 */
+            maj = (pvr >> 8) & 0x0F;
+            min = pvr & 0xFF;
+            break;
+        default:
+            maj = (pvr >> 8) & 0xFF;
+            min = pvr & 0xFF;
+            break;
+        }
+    }
+
+    if (clock_getres(CLOCK_REALTIME, &res) == -1) {
+        res.tv_nsec = 1;
+    }
+    freq_mhz = 1000.0 / res.tv_nsec;
+
+    num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+    for (i = 0; i < num_cpus; i++) {
+        dprintf(fd, "processor\t: %d\n", i);
+        dprintf(fd, "cpu\t\t: %s%s\n",
+                    dc->desc,
+                    pcc->insns_flags & PPC_ALTIVEC ? ", altivec supported":"");
+        dprintf(fd, "clock\t\t: %.3fMHz\n", freq_mhz);
+        dprintf(fd, "revision\t: %d.%d (pvr %04x %04x)\n\n",
+                    maj, min, PVR_VER(pvr), PVR_REV(pvr));
+    }
+
+    dprintf(fd, "timebase\t: 1000000000\n");
+    dprintf(fd, "platform\t: pSeries\n");
+    dprintf(fd, "model\t\t: IBM pSeries (QEMU user v" QEMU_VERSION ")\n");
+    dprintf(fd, "machine\t\t: CHRP IBM pSeries\n");
+
+    return 0;
+}
+#define HAVE_ARCH_PROC_CPUINFO
+
+#endif /* PPC_TARGET_PROC_H */
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PULL 3/4] target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status
  2026-06-12 15:50 [PULL 0/4] Linux user patches Helge Deller
  2026-06-12 15:50 ` [PULL 1/4] linux-user: add preadv2/preadv2 Helge Deller
  2026-06-12 15:50 ` [PULL 2/4] linux-user: Implement /proc/cpuinfo for ppc cpus Helge Deller
@ 2026-06-12 15:50 ` Helge Deller
  2026-06-12 15:50 ` [PULL 4/4] linux-user/xtensa: save/restore FP registers across signal delivery Helge Deller
  3 siblings, 0 replies; 5+ messages in thread
From: Helge Deller @ 2026-06-12 15:50 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel
  Cc: Helge Deller, Pierrick Bouvier, Laurent Vivier, Max Filippov,
	Matt Turner, Richard Henderson

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.

Signed-off-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Helge Deller <deller@gmx.de>
---
 target/xtensa/cpu.h        |  4 +++
 target/xtensa/fpu_helper.c | 71 +++++++++++++++++++++-----------------
 2 files changed, 44 insertions(+), 31 deletions(-)

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..2e51cabe3f 100644
--- a/target/xtensa/fpu_helper.c
+++ b/target/xtensa/fpu_helper.c
@@ -64,46 +64,39 @@ void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
                              &env->fp_status);
 }
 
-void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
+uint32_t cpu_get_fsr(CPUXtensaState *env)
 {
-    static const int rounding_mode[] = {
-        float_round_nearest_even,
-        float_round_to_zero,
-        float_round_up,
-        float_round_down,
-    };
+    uint32_t flags = 0;
+    int fef = get_float_exception_flags(&env->fp_status);
+    unsigned i;
 
-    env->uregs[FCR] = v & 0xfffff07f;
-    set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
+    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 HELPER(wur_fpu_fcr)(CPUXtensaState *env, uint32_t v)
+void cpu_set_fcr(CPUXtensaState *env, uint32_t v)
 {
-    static const int rounding_mode[] = {
+    static const FloatRoundMode rounding_mode[] = {
         float_round_nearest_even,
         float_round_to_zero,
         float_round_up,
         float_round_down,
     };
 
-    if (v & 0xfffff000) {
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "MBZ field of FCR is written non-zero: %08x\n", v);
-    }
-    env->uregs[FCR] = v & 0x0000007f;
+    env->uregs[FCR] = v & 0xfffff07f;
     set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
 }
 
-void HELPER(wur_fpu_fsr)(CPUXtensaState *env, uint32_t v)
+void cpu_set_fsr(CPUXtensaState *env, uint32_t v)
 {
     uint32_t flags = v >> XTENSA_FSR_FLAGS_SHIFT;
     int fef = 0;
     unsigned i;
 
-    if (v & 0xfffff000) {
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "MBZ field of FSR is written non-zero: %08x\n", v);
-    }
     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) {
@@ -113,19 +106,35 @@ void HELPER(wur_fpu_fsr)(CPUXtensaState *env, uint32_t v)
     set_float_exception_flags(fef, &env->fp_status);
 }
 
-uint32_t HELPER(rur_fpu_fsr)(CPUXtensaState *env)
+void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
 {
-    uint32_t flags = 0;
-    int fef = get_float_exception_flags(&env->fp_status);
-    unsigned i;
+    cpu_set_fcr(env, v);
+}
 
-    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;
-        }
+void HELPER(wur_fpu_fcr)(CPUXtensaState *env, uint32_t v)
+{
+    if (v & 0xfffff000) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "MBZ field of FCR is written non-zero: %08x\n", v);
     }
-    env->uregs[FSR] = flags << XTENSA_FSR_FLAGS_SHIFT;
-    return flags << XTENSA_FSR_FLAGS_SHIFT;
+    cpu_set_fcr(env, v & 0x0000007f);
+}
+
+void HELPER(wur_fpu_fsr)(CPUXtensaState *env, uint32_t v)
+{
+    if (v & 0xfffff000) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "MBZ field of FSR is written non-zero: %08x\n", v);
+    }
+    cpu_set_fsr(env, v);
+}
+
+uint32_t HELPER(rur_fpu_fsr)(CPUXtensaState *env)
+{
+    uint32_t fsr = cpu_get_fsr(env);
+
+    env->uregs[FSR] = fsr;
+    return fsr;
 }
 
 float64 HELPER(abs_d)(float64 v)
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PULL 4/4] linux-user/xtensa: save/restore FP registers across signal delivery
  2026-06-12 15:50 [PULL 0/4] Linux user patches Helge Deller
                   ` (2 preceding siblings ...)
  2026-06-12 15:50 ` [PULL 3/4] target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status Helge Deller
@ 2026-06-12 15:50 ` Helge Deller
  3 siblings, 0 replies; 5+ messages in thread
From: Helge Deller @ 2026-06-12 15:50 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel
  Cc: Helge Deller, Pierrick Bouvier, Laurent Vivier, Max Filippov,
	Matt Turner, Richard Henderson

From: Matt Turner <mattst88@gmail.com>

Add support for saving and restoring f0-f15 across signal delivery.
The target_xtensa_xtregs_fp struct carries 32-bit f-regs for cores
with XTENSA_OPTION_FP_COPROCESSOR; target_xtensa_xtregs_dfp carries
64-bit f-regs for cores with XTENSA_OPTION_DFP_COPROCESSOR.

Lock the xtregs region via lock_user before reading on sigreturn,
since sc_xtregs is a user-space pointer that may lie outside the
locked sigframe.

Signed-off-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Helge Deller <deller@gmx.de>
---
 linux-user/xtensa/signal.c | 96 ++++++++++++++++++++++++++++++++++----
 1 file changed, 88 insertions(+), 8 deletions(-)

diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
index ef8b0c3a27..e3f9da322b 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,25 @@ struct target_ucontext {
     target_sigset_t tuc_sigmask;
 };
 
+struct target_xtensa_xtregs_fp {
+    uint32_t f[16];
+    uint32_t fcr;
+    uint32_t fsr;
+};
+
+struct target_xtensa_xtregs_dfp {
+    uint64_t f[16];
+    uint32_t fcr;
+    uint32_t fsr;
+};
+
 struct target_rt_sigframe {
     target_siginfo_t info;
     struct target_ucontext uc;
-    /* TODO: xtregs */
+    union {
+        struct target_xtensa_xtregs_fp fp;
+        struct target_xtensa_xtregs_dfp dfp;
+    } xtregs;
     uint8_t retcode[6];
     abi_ulong window[4];
 };
@@ -107,6 +123,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 +140,25 @@ 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_DFP_COPROCESSOR)) {
+        for (i = 0; i < 16; ++i) {
+            __put_user(env->fregs[i].f64, &frame->xtregs.dfp.f[i]);
+        }
+        __put_user(env->uregs[FCR], &frame->xtregs.dfp.fcr);
+        __put_user(cpu_get_fsr(env), &frame->xtregs.dfp.fsr);
+        __put_user(frame_addr + offsetof(struct target_rt_sigframe, xtregs),
+                   &sc->sc_xtregs);
+    } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_FP_COPROCESSOR)) {
+        for (i = 0; i < 16; ++i) {
+            __put_user(env->fregs[i].f32[FP_F32_LOW], &frame->xtregs.fp.f[i]);
+        }
+        __put_user(env->uregs[FCR], &frame->xtregs.fp.fcr);
+        __put_user(cpu_get_fsr(env), &frame->xtregs.fp.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 +224,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;
     }
@@ -243,8 +277,8 @@ give_sigsegv:
     force_sigsegv(sig);
 }
 
-static void restore_sigcontext(CPUXtensaState *env,
-                               struct target_rt_sigframe *frame)
+static int restore_sigcontext(CPUXtensaState *env,
+                              struct target_rt_sigframe *frame)
 {
     struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
     uint32_t ps;
@@ -266,7 +300,51 @@ 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) {
+            if (xtensa_option_enabled(env->config,
+                                      XTENSA_OPTION_DFP_COPROCESSOR)) {
+                struct target_xtensa_xtregs_dfp *xtregs;
+                uint32_t fcr, fsr;
+
+                xtregs = lock_user(VERIFY_READ, xtregs_addr,
+                                   sizeof(*xtregs), 1);
+                if (!xtregs) {
+                    return 0;
+                }
+                for (i = 0; i < 16; ++i) {
+                    __get_user(env->fregs[i].f64, &xtregs->f[i]);
+                }
+                __get_user(fcr, &xtregs->fcr);
+                __get_user(fsr, &xtregs->fsr);
+                unlock_user(xtregs, xtregs_addr, 0);
+                cpu_set_fcr(env, fcr);
+                cpu_set_fsr(env, fsr);
+            } else if (xtensa_option_enabled(env->config,
+                                             XTENSA_OPTION_FP_COPROCESSOR)) {
+                struct target_xtensa_xtregs_fp *xtregs;
+                uint32_t fcr, fsr;
+
+                xtregs = lock_user(VERIFY_READ, xtregs_addr,
+                                   sizeof(*xtregs), 1);
+                if (!xtregs) {
+                    return 0;
+                }
+                for (i = 0; i < 16; ++i) {
+                    __get_user(env->fregs[i].f32[FP_F32_LOW], &xtregs->f[i]);
+                }
+                __get_user(fcr, &xtregs->fcr);
+                __get_user(fsr, &xtregs->fsr);
+                unlock_user(xtregs, xtregs_addr, 0);
+                cpu_set_fcr(env, fcr);
+                cpu_set_fsr(env, fsr);
+            }
+        }
+    }
+    return 1;
 }
 
 long do_rt_sigreturn(CPUXtensaState *env)
@@ -282,7 +360,9 @@ long do_rt_sigreturn(CPUXtensaState *env)
     target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
     set_sigmask(&set);
 
-    restore_sigcontext(env, frame);
+    if (!restore_sigcontext(env, frame)) {
+        goto badframe;
+    }
     target_restore_altstack(&frame->uc.tuc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-06-12 15:52 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-12 15:50 [PULL 0/4] Linux user patches Helge Deller
2026-06-12 15:50 ` [PULL 1/4] linux-user: add preadv2/preadv2 Helge Deller
2026-06-12 15:50 ` [PULL 2/4] linux-user: Implement /proc/cpuinfo for ppc cpus Helge Deller
2026-06-12 15:50 ` [PULL 3/4] target/xtensa: add cpu_set_fcr/fsr helpers to sync fp_status Helge Deller
2026-06-12 15:50 ` [PULL 4/4] linux-user/xtensa: save/restore FP registers across signal delivery Helge Deller

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.