#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;
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];
};
}
static int setup_sigcontext(struct target_rt_sigframe *frame,
+ abi_ulong frame_addr,
CPUXtensaState *env)
{
struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
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;
}
__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;
}
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;
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)
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);