mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:17 +00:00
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>
This commit is contained in:
committed by
Helge Deller
parent
7e859bacea
commit
6858e3a71c
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user