@samitouri / QOSamiQemu / commits / 6858e3a71c

linux-user/xtensa: save/restore FP registers across signal delivery

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>

Matt Turner committed Jun 12, 2026 at 10:14 UTC 6858e3a71cc41510937bec0950eb4e42e33ba5f2
1 file changed +88 -8
linux-user/xtensa/signal.c
+88 -8
@@ -21,6 +21,7 @@
21 #include "user-internals.h"
22 #include "signal-common.h"
23 #include "linux-user/trace.h"
24 +#include "target/xtensa/cpu.h"
25
26 struct target_sigcontext {
27 abi_ulong sc_pc;
@@ -43,10 +44,25 @@ struct target_ucontext {
44 target_sigset_t tuc_sigmask;
45 };
46
47 +struct target_xtensa_xtregs_fp {
48 + uint32_t f[16];
49 + uint32_t fcr;
50 + uint32_t fsr;
51 +};
52 +
53 +struct target_xtensa_xtregs_dfp {
54 + uint64_t f[16];
55 + uint32_t fcr;
56 + uint32_t fsr;
57 +};
58 +
59 struct target_rt_sigframe {
60 target_siginfo_t info;
61 struct target_ucontext uc;
49 - /* TODO: xtregs */
62 + union {
63 + struct target_xtensa_xtregs_fp fp;
64 + struct target_xtensa_xtregs_dfp dfp;
65 + } xtregs;
66 uint8_t retcode[6];
67 abi_ulong window[4];
68 };
@@ -107,6 +123,7 @@ static int flush_window_regs(CPUXtensaState *env)
123 }
124
125 static int setup_sigcontext(struct target_rt_sigframe *frame,
126 + abi_ulong frame_addr,
127 CPUXtensaState *env)
128 {
129 struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
@@ -123,8 +140,25 @@ static int setup_sigcontext(struct target_rt_sigframe *frame,
140 for (i = 0; i < 16; ++i) {
141 __put_user(env->regs[i], sc->sc_a + i);
142 }
126 - __put_user(0, &sc->sc_xtregs);
127 - /* TODO: xtregs */
143 + if (xtensa_option_enabled(env->config, XTENSA_OPTION_DFP_COPROCESSOR)) {
144 + for (i = 0; i < 16; ++i) {
145 + __put_user(env->fregs[i].f64, &frame->xtregs.dfp.f[i]);
146 + }
147 + __put_user(env->uregs[FCR], &frame->xtregs.dfp.fcr);
148 + __put_user(cpu_get_fsr(env), &frame->xtregs.dfp.fsr);
149 + __put_user(frame_addr + offsetof(struct target_rt_sigframe, xtregs),
150 + &sc->sc_xtregs);
151 + } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_FP_COPROCESSOR)) {
152 + for (i = 0; i < 16; ++i) {
153 + __put_user(env->fregs[i].f32[FP_F32_LOW], &frame->xtregs.fp.f[i]);
154 + }
155 + __put_user(env->uregs[FCR], &frame->xtregs.fp.fcr);
156 + __put_user(cpu_get_fsr(env), &frame->xtregs.fp.fsr);
157 + __put_user(frame_addr + offsetof(struct target_rt_sigframe, xtregs),
158 + &sc->sc_xtregs);
159 + } else {
160 + __put_user(0, &sc->sc_xtregs);
161 + }
162 return 1;
163 }
164
@@ -190,7 +224,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
224 __put_user(0, &frame->uc.tuc_flags);
225 __put_user(0, &frame->uc.tuc_link);
226 target_save_altstack(&frame->uc.tuc_stack, env);
193 - if (!setup_sigcontext(frame, env)) {
227 + if (!setup_sigcontext(frame, frame_addr, env)) {
228 unlock_user_struct(frame, frame_addr, 0);
229 goto give_sigsegv;
230 }
@@ -243,8 +277,8 @@ give_sigsegv:
277 force_sigsegv(sig);
278 }
279
246 -static void restore_sigcontext(CPUXtensaState *env,
247 - struct target_rt_sigframe *frame)
280 +static int restore_sigcontext(CPUXtensaState *env,
281 + struct target_rt_sigframe *frame)
282 {
283 struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
284 uint32_t ps;
@@ -266,7 +300,51 @@ static void restore_sigcontext(CPUXtensaState *env,
300 for (i = 0; i < 16; ++i) {
301 __get_user(env->regs[i], sc->sc_a + i);
302 }
269 - /* TODO: xtregs */
303 + {
304 + abi_ulong xtregs_addr;
305 +
306 + __get_user(xtregs_addr, &sc->sc_xtregs);
307 + if (xtregs_addr) {
308 + if (xtensa_option_enabled(env->config,
309 + XTENSA_OPTION_DFP_COPROCESSOR)) {
310 + struct target_xtensa_xtregs_dfp *xtregs;
311 + uint32_t fcr, fsr;
312 +
313 + xtregs = lock_user(VERIFY_READ, xtregs_addr,
314 + sizeof(*xtregs), 1);
315 + if (!xtregs) {
316 + return 0;
317 + }
318 + for (i = 0; i < 16; ++i) {
319 + __get_user(env->fregs[i].f64, &xtregs->f[i]);
320 + }
321 + __get_user(fcr, &xtregs->fcr);
322 + __get_user(fsr, &xtregs->fsr);
323 + unlock_user(xtregs, xtregs_addr, 0);
324 + cpu_set_fcr(env, fcr);
325 + cpu_set_fsr(env, fsr);
326 + } else if (xtensa_option_enabled(env->config,
327 + XTENSA_OPTION_FP_COPROCESSOR)) {
328 + struct target_xtensa_xtregs_fp *xtregs;
329 + uint32_t fcr, fsr;
330 +
331 + xtregs = lock_user(VERIFY_READ, xtregs_addr,
332 + sizeof(*xtregs), 1);
333 + if (!xtregs) {
334 + return 0;
335 + }
336 + for (i = 0; i < 16; ++i) {
337 + __get_user(env->fregs[i].f32[FP_F32_LOW], &xtregs->f[i]);
338 + }
339 + __get_user(fcr, &xtregs->fcr);
340 + __get_user(fsr, &xtregs->fsr);
341 + unlock_user(xtregs, xtregs_addr, 0);
342 + cpu_set_fcr(env, fcr);
343 + cpu_set_fsr(env, fsr);
344 + }
345 + }
346 + }
347 + return 1;
348 }
349
350 long do_rt_sigreturn(CPUXtensaState *env)
@@ -282,7 +360,9 @@ long do_rt_sigreturn(CPUXtensaState *env)
360 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
361 set_sigmask(&set);
362
285 - restore_sigcontext(env, frame);
363 + if (!restore_sigcontext(env, frame)) {
364 + goto badframe;
365 + }
366 target_restore_altstack(&frame->uc.tuc_stack, env);
367
368 unlock_user_struct(frame, frame_addr, 0);