return -TARGET_QEMU_ESIGRETURN;
}
+ #elif defined(TARGET_XTENSA)
+
+ struct target_sigcontext {
+ abi_ulong sc_pc;
+ abi_ulong sc_ps;
+ abi_ulong sc_lbeg;
+ abi_ulong sc_lend;
+ abi_ulong sc_lcount;
+ abi_ulong sc_sar;
+ abi_ulong sc_acclo;
+ abi_ulong sc_acchi;
+ abi_ulong sc_a[16];
+ abi_ulong sc_xtregs;
+ };
+
+ struct target_ucontext {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask;
+ };
+
+ struct target_rt_sigframe {
+ target_siginfo_t info;
+ struct target_ucontext uc;
+ /* TODO: xtregs */
+ uint8_t retcode[6];
+ abi_ulong window[4];
+ };
+
+ static abi_ulong get_sigframe(struct target_sigaction *sa,
+ CPUXtensaState *env,
+ unsigned long framesize)
+ {
+ abi_ulong sp = env->regs[1];
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
+ sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+ }
+ return (sp - framesize) & -16;
+ }
+
+ static int flush_window_regs(CPUXtensaState *env)
+ {
+ const uint32_t nareg_mask = env->config->nareg - 1;
+ uint32_t wb = env->sregs[WINDOW_BASE];
+ uint32_t ws = (xtensa_replicate_windowstart(env) >> (wb + 1)) &
+ ((1 << env->config->nareg / 4) - 1);
+ uint32_t d = ctz32(ws) + 1;
+ uint32_t sp;
+ abi_long ret = 0;
+
+ wb += d;
+ ws >>= d;
+
+ xtensa_sync_phys_from_window(env);
+ sp = env->phys_regs[(wb * 4 + 1) & nareg_mask];
+
+ while (ws && ret == 0) {
+ int d;
+ int i;
+ int idx;
+
+ if (ws & 0x1) {
+ ws >>= 1;
+ d = 1;
+ } else if (ws & 0x2) {
+ ws >>= 2;
+ d = 2;
+ for (i = 0; i < 4; ++i) {
+ idx = (wb * 4 + 4 + i) & nareg_mask;
+ ret |= put_user_ual(env->phys_regs[idx], sp + (i - 12) * 4);
+ }
+ } else if (ws & 0x4) {
+ ws >>= 3;
+ d = 3;
+ for (i = 0; i < 8; ++i) {
+ idx = (wb * 4 + 4 + i) & nareg_mask;
+ ret |= put_user_ual(env->phys_regs[idx], sp + (i - 16) * 4);
+ }
+ } else {
+ g_assert_not_reached();
+ }
+ sp = env->phys_regs[((wb + d) * 4 + 1) & nareg_mask];
+ for (i = 0; i < 4; ++i) {
+ idx = (wb * 4 + i) & nareg_mask;
+ ret |= put_user_ual(env->phys_regs[idx], sp + (i - 4) * 4);
+ }
+ wb += d;
+ }
+ return ret == 0;
+ }
+
+ static int setup_sigcontext(struct target_rt_sigframe *frame,
+ CPUXtensaState *env)
+ {
+ struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
+ int i;
+
+ __put_user(env->pc, &sc->sc_pc);
+ __put_user(env->sregs[PS], &sc->sc_ps);
+ __put_user(env->sregs[LBEG], &sc->sc_lbeg);
+ __put_user(env->sregs[LEND], &sc->sc_lend);
+ __put_user(env->sregs[LCOUNT], &sc->sc_lcount);
+ if (!flush_window_regs(env)) {
+ return 0;
+ }
+ for (i = 0; i < 16; ++i) {
+ __put_user(env->regs[i], sc->sc_a + i);
+ }
+ __put_user(0, &sc->sc_xtregs);
+ /* TODO: xtregs */
+ return 1;
+ }
+
+ static void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUXtensaState *env)
+ {
+ abi_ulong frame_addr;
+ struct target_rt_sigframe *frame;
+ uint32_t ra;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_rt_frame(env, frame_addr);
+
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ if (ka->sa_flags & SA_SIGINFO) {
+ tswap_siginfo(&frame->info, info);
+ }
+
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user(0, &frame->uc.tuc_link);
+ __put_user(target_sigaltstack_used.ss_sp,
+ &frame->uc.tuc_stack.ss_sp);
+ __put_user(sas_ss_flags(env->regs[1]),
+ &frame->uc.tuc_stack.ss_flags);
+ __put_user(target_sigaltstack_used.ss_size,
+ &frame->uc.tuc_stack.ss_size);
+ if (!setup_sigcontext(frame, env)) {
+ unlock_user_struct(frame, frame_addr, 0);
+ goto give_sigsegv;
+ }
+ for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
+ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+ }
+
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ ra = ka->sa_restorer;
+ } else {
+ ra = frame_addr + offsetof(struct target_rt_sigframe, retcode);
+ #ifdef TARGET_WORDS_BIGENDIAN
+ /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
+ __put_user(0x22, &frame->retcode[0]);
+ __put_user(0x0a, &frame->retcode[1]);
+ __put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]);
+ /* Generate instruction: SYSCALL */
+ __put_user(0x00, &frame->retcode[3]);
+ __put_user(0x05, &frame->retcode[4]);
+ __put_user(0x00, &frame->retcode[5]);
+ #else
+ /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
+ __put_user(0x22, &frame->retcode[0]);
+ __put_user(0xa0, &frame->retcode[1]);
+ __put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]);
+ /* Generate instruction: SYSCALL */
+ __put_user(0x00, &frame->retcode[3]);
+ __put_user(0x50, &frame->retcode[4]);
+ __put_user(0x00, &frame->retcode[5]);
+ #endif
+ }
+ env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT);
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER)) {
+ env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT);
+ }
+ memset(env->regs, 0, sizeof(env->regs));
+ env->pc = ka->_sa_handler;
+ env->regs[1] = frame_addr;
+ env->sregs[WINDOW_BASE] = 0;
+ env->sregs[WINDOW_START] = 1;
+
+ env->regs[4] = (ra & 0x3fffffff) | 0x40000000;
+ env->regs[6] = sig;
+ env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, info);
+ env->regs[8] = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+ give_sigsegv:
+ force_sigsegv(sig);
+ return;
+ }
+
+ static void restore_sigcontext(CPUXtensaState *env,
+ struct target_rt_sigframe *frame)
+ {
+ struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
+ uint32_t ps;
+ int i;
+
+ __get_user(env->pc, &sc->sc_pc);
+ __get_user(ps, &sc->sc_ps);
+ __get_user(env->sregs[LBEG], &sc->sc_lbeg);
+ __get_user(env->sregs[LEND], &sc->sc_lend);
+ __get_user(env->sregs[LCOUNT], &sc->sc_lcount);
+
+ env->sregs[WINDOW_BASE] = 0;
+ env->sregs[WINDOW_START] = 1;
+ env->sregs[PS] = deposit32(env->sregs[PS],
+ PS_CALLINC_SHIFT,
+ PS_CALLINC_LEN,
+ extract32(ps, PS_CALLINC_SHIFT,
+ PS_CALLINC_LEN));
+ for (i = 0; i < 16; ++i) {
+ __get_user(env->regs[i], sc->sc_a + i);
+ }
+ /* TODO: xtregs */
+ }
+
+ long do_rt_sigreturn(CPUXtensaState *env)
+ {
+ abi_ulong frame_addr = env->regs[1];
+ struct target_rt_sigframe *frame;
+ sigset_t set;
+
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+ set_sigmask(&set);
+
+ restore_sigcontext(env, frame);
+
+ if (do_sigaltstack(frame_addr +
+ offsetof(struct target_rt_sigframe, uc.tuc_stack),
+ 0, get_sp_from_cpustate(env)) == -TARGET_EFAULT) {
+ goto badframe;
+ }
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+ badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+ }
+
#else
-
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUArchState *env)
-{
- fprintf(stderr, "setup_frame: not implemented\n");
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUArchState *env)
-{
- fprintf(stderr, "setup_rt_frame: not implemented\n");
-}
-
-long do_sigreturn(CPUArchState *env)
-{
- fprintf(stderr, "do_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
-long do_rt_sigreturn(CPUArchState *env)
-{
- fprintf(stderr, "do_rt_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
+#error Target needs to add support for signal handling
#endif
static void handle_pending_signal(CPUArchState *cpu_env, int sig,