X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=linux-user%2Fsignal.c;h=8ee5c4b2fdbc406b71c0e5eb642218686708749b;hb=c35734b2a6f9b028edacd5813ff271728ce2a9e3;hp=bde492237b86364af33e7580743b43d688c41725;hpb=9231944d9669595cecee8dda969546216470d6ad;p=qemu diff --git a/linux-user/signal.c b/linux-user/signal.c index bde4922..8ee5c4b 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -26,13 +26,6 @@ #include #include -#ifdef __ia64__ -#undef uc_mcontext -#undef uc_sigmask -#undef uc_stack -#undef uc_link -#endif - #include "qemu.h" //#define DEBUG_SIGNAL @@ -131,7 +124,7 @@ static void host_to_target_sigset_internal(target_sigset_t *d, d->sig[0] = target_sigmask; d->sig[1] = sigmask >> 32; #else -#error host_to_target_sigset +#warning host_to_target_sigset #endif } @@ -142,7 +135,7 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) host_to_target_sigset_internal(&d1, s); for(i = 0;i < TARGET_NSIG_WORDS; i++) - __put_user(d1.sig[i], &d->sig[i]); + d->sig[i] = tswapl(d1.sig[i]); } void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) @@ -165,7 +158,7 @@ void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) #elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 ((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32); #else -#error target_to_host_sigset +#warning target_to_host_sigset #endif /* TARGET_LONG_BITS */ } @@ -175,7 +168,7 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) int i; for(i = 0;i < TARGET_NSIG_WORDS; i++) - __get_user(s1.sig[i], &s->sig[i]); + s1.sig[i] = tswapl(s->sig[i]); target_to_host_sigset_internal(d, &s1); } @@ -439,13 +432,17 @@ int do_sigaction(int sig, const struct target_sigaction *act, if (oact) { oact->_sa_handler = tswapl(k->sa._sa_handler); oact->sa_flags = tswapl(k->sa.sa_flags); - oact->sa_restorer = tswapl(k->sa.sa_restorer); + #if !defined(TARGET_MIPS) + oact->sa_restorer = tswapl(k->sa.sa_restorer); + #endif oact->sa_mask = k->sa.sa_mask; } if (act) { k->sa._sa_handler = tswapl(act->_sa_handler); k->sa.sa_flags = tswapl(act->sa_flags); - k->sa.sa_restorer = tswapl(act->sa_restorer); + #if !defined(TARGET_MIPS) + k->sa.sa_restorer = tswapl(act->sa_restorer); + #endif k->sa.sa_mask = act->sa_mask; /* we update the host linux signal state */ @@ -557,11 +554,11 @@ typedef struct target_sigaltstack { } target_stack_t; struct target_ucontext { - target_ulong uc_flags; - target_ulong uc_link; - target_stack_t uc_stack; - struct target_sigcontext uc_mcontext; - target_sigset_t uc_sigmask; /* mask last for extensibility */ + target_ulong tuc_flags; + target_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ }; struct sigframe @@ -654,7 +651,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) ka->sa.sa_restorer) { esp = (unsigned long) ka->sa.sa_restorer; } - return (void *)((esp - frame_size) & -8ul); + return g2h((esp - frame_size) & -8ul); } static void setup_frame(int sig, struct emulated_sigaction *ka, @@ -701,7 +698,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, goto give_sigsegv; /* Set up registers for signal handler */ - env->regs[R_ESP] = (unsigned long) frame; + env->regs[R_ESP] = h2g(frame); env->eip = (unsigned long) ka->sa._sa_handler; cpu_x86_load_seg(env, R_DS, __USER_DS); @@ -743,16 +740,18 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, goto give_sigsegv; /* Create the ucontext. */ - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(/*current->sas_ss_sp*/ 0, &frame->uc.uc_stack.ss_sp); + err |= __put_user(0, &frame->uc.tuc_flags); + err |= __put_user(0, &frame->uc.tuc_link); + err |= __put_user(/*current->sas_ss_sp*/ 0, + &frame->uc.tuc_stack.ss_sp); err |= __put_user(/* sas_ss_flags(regs->esp) */ 0, - &frame->uc.uc_stack.ss_flags); - err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, + &frame->uc.tuc_stack.ss_flags); + err |= __put_user(/* current->sas_ss_size */ 0, + &frame->uc.tuc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env, set->sig[0]); for(i = 0; i < TARGET_NSIG_WORDS; i++) { - if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i])) + if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) goto give_sigsegv; } @@ -840,7 +839,7 @@ badframe: long do_sigreturn(CPUX86State *env) { - struct sigframe *frame = (struct sigframe *)(env->regs[R_ESP] - 8); + struct sigframe *frame = (struct sigframe *)g2h(env->regs[R_ESP] - 8); target_sigset_t target_set; sigset_t set; int eax, i; @@ -871,7 +870,7 @@ badframe: long do_rt_sigreturn(CPUX86State *env) { - struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4); + struct rt_sigframe *frame = (struct rt_sigframe *)g2h(env->regs[R_ESP] - 4); sigset_t set; // stack_t st; int eax; @@ -880,14 +879,14 @@ long do_rt_sigreturn(CPUX86State *env) if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; #endif - target_to_host_sigset(&set, &frame->uc.uc_sigmask); + target_to_host_sigset(&set, &frame->uc.tuc_sigmask); sigprocmask(SIG_SETMASK, &set, NULL); - if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax)) + if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) goto badframe; #if 0 - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + if (__copy_from_user(&st, &frame->uc.tuc_stack, sizeof(st))) goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ @@ -933,11 +932,11 @@ typedef struct target_sigaltstack { } target_stack_t; struct target_ucontext { - target_ulong uc_flags; - target_ulong uc_link; - target_stack_t uc_stack; - struct target_sigcontext uc_mcontext; - target_sigset_t uc_sigmask; /* mask last for extensibility */ + target_ulong tuc_flags; + target_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ }; struct sigframe @@ -1008,7 +1007,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ __put_user_error(env->regs[14], &sc->arm_lr, err); __put_user_error(env->regs[15], &sc->arm_pc, err); #ifdef TARGET_CONFIG_CPU_32 - __put_user_error(env->cpsr, &sc->arm_cpsr, err); + __put_user_error(cpsr_read(env), &sc->arm_cpsr, err); #endif __put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err); @@ -1034,7 +1033,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) /* * ATPCS B01 mandates 8-byte alignment */ - return (void *)((sp - framesize) & ~7); + return g2h((sp - framesize) & ~7); } static int @@ -1045,9 +1044,9 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, target_ulong retcode; int thumb = 0; #if defined(TARGET_CONFIG_CPU_32) +#if 0 target_ulong cpsr = env->cpsr; -#if 0 /* * Maybe we need to deliver a 32-bit signal to a 26-bit task. */ @@ -1089,13 +1088,15 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, } env->regs[0] = usig; - env->regs[13] = (target_ulong)frame; + env->regs[13] = h2g(frame); env->regs[14] = retcode; env->regs[15] = handler & (thumb ? ~1 : ~3); +#if 0 #ifdef TARGET_CONFIG_CPU_32 env->cpsr = cpsr; #endif +#endif return 0; } @@ -1133,12 +1134,12 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, err |= copy_siginfo_to_user(&frame->info, info); /* Clear all the bits of the ucontext we don't use. */ - err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + memset(&frame->uc, 0, offsetof(struct target_ucontext, tuc_mcontext)); - err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/ + err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ env, set->sig[0]); for(i = 0; i < TARGET_NSIG_WORDS; i++) { - if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i])) + if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) return; } @@ -1162,6 +1163,7 @@ static int restore_sigcontext(CPUState *env, struct target_sigcontext *sc) { int err = 0; + uint32_t cpsr; __get_user_error(env->regs[0], &sc->arm_r0, err); __get_user_error(env->regs[1], &sc->arm_r1, err); @@ -1180,7 +1182,8 @@ restore_sigcontext(CPUState *env, struct target_sigcontext *sc) __get_user_error(env->regs[14], &sc->arm_lr, err); __get_user_error(env->regs[15], &sc->arm_pc, err); #ifdef TARGET_CONFIG_CPU_32 - __get_user_error(env->cpsr, &sc->arm_cpsr, err); + __get_user_error(cpsr, &sc->arm_cpsr, err); + cpsr_write(env, cpsr, 0xffffffff); #endif err |= !valid_user_regs(env); @@ -1203,7 +1206,7 @@ long do_sigreturn(CPUState *env) if (env->regs[13] & 7) goto badframe; - frame = (struct sigframe *)env->regs[13]; + frame = (struct sigframe *)g2h(env->regs[13]); #if 0 if (verify_area(VERIFY_READ, frame, sizeof (*frame))) @@ -1253,10 +1256,10 @@ long do_rt_sigreturn(CPUState *env) if (verify_area(VERIFY_READ, frame, sizeof (*frame))) goto badframe; #endif - target_to_host_sigset(&host_set, &frame->uc.uc_sigmask); + target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask); sigprocmask(SIG_SETMASK, &host_set, NULL); - if (restore_sigcontext(env, &frame->uc.uc_mcontext)) + if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) goto badframe; #if 0 @@ -1271,6 +1274,686 @@ badframe: return 0; } +#elif defined(TARGET_SPARC) + +#define __SUNOS_MAXWIN 31 + +/* This is what SunOS does, so shall I. */ +struct target_sigcontext { + target_ulong sigc_onstack; /* state to restore */ + + target_ulong sigc_mask; /* sigmask to restore */ + target_ulong sigc_sp; /* stack pointer */ + target_ulong sigc_pc; /* program counter */ + target_ulong sigc_npc; /* next program counter */ + target_ulong sigc_psr; /* for condition codes etc */ + target_ulong sigc_g1; /* User uses these two registers */ + target_ulong sigc_o0; /* within the trampoline code. */ + + /* Now comes information regarding the users window set + * at the time of the signal. + */ + target_ulong sigc_oswins; /* outstanding windows */ + + /* stack ptrs for each regwin buf */ + char *sigc_spbuf[__SUNOS_MAXWIN]; + + /* Windows to restore after signal */ + struct { + target_ulong locals[8]; + target_ulong ins[8]; + } sigc_wbuf[__SUNOS_MAXWIN]; +}; +/* A Sparc stack frame */ +struct sparc_stackf { + target_ulong locals[8]; + target_ulong ins[6]; + struct sparc_stackf *fp; + target_ulong callers_pc; + char *structptr; + target_ulong xargs[6]; + target_ulong xxargs[1]; +}; + +typedef struct { + struct { + target_ulong psr; + target_ulong pc; + target_ulong npc; + target_ulong y; + target_ulong u_regs[16]; /* globals and ins */ + } si_regs; + int si_mask; +} __siginfo_t; + +typedef struct { + unsigned long si_float_regs [32]; + unsigned long si_fsr; + unsigned long si_fpqdepth; + struct { + unsigned long *insn_addr; + unsigned long insn; + } si_fpqueue [16]; +} qemu_siginfo_fpu_t; + + +struct target_signal_frame { + struct sparc_stackf ss; + __siginfo_t info; + qemu_siginfo_fpu_t *fpu_save; + target_ulong insns[2] __attribute__ ((aligned (8))); + target_ulong extramask[TARGET_NSIG_WORDS - 1]; + target_ulong extra_size; /* Should be 0 */ + qemu_siginfo_fpu_t fpu_state; +}; +struct target_rt_signal_frame { + struct sparc_stackf ss; + siginfo_t info; + target_ulong regs[20]; + sigset_t mask; + qemu_siginfo_fpu_t *fpu_save; + unsigned int insns[2]; + stack_t stack; + unsigned int extra_size; /* Should be 0 */ + qemu_siginfo_fpu_t fpu_state; +}; + +#define UREG_O0 16 +#define UREG_O6 22 +#define UREG_I0 0 +#define UREG_I1 1 +#define UREG_I2 2 +#define UREG_I6 6 +#define UREG_I7 7 +#define UREG_L0 8 +#define UREG_FP UREG_I6 +#define UREG_SP UREG_O6 + +static inline void *get_sigframe(struct emulated_sigaction *sa, CPUState *env, unsigned long framesize) +{ + unsigned long sp; + + sp = env->regwptr[UREG_FP]; +#if 0 + + /* This is the X/Open sanctioned signal stack switching. */ + if (sa->sa_flags & TARGET_SA_ONSTACK) { + if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) + sp = current->sas_ss_sp + current->sas_ss_size; + } +#endif + return g2h(sp - framesize); +} + +static int +setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask) +{ + int err = 0, i; + + err |= __put_user(env->psr, &si->si_regs.psr); + err |= __put_user(env->pc, &si->si_regs.pc); + err |= __put_user(env->npc, &si->si_regs.npc); + err |= __put_user(env->y, &si->si_regs.y); + for (i=0; i < 8; i++) { + err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]); + } + for (i=0; i < 8; i++) { + err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]); + } + err |= __put_user(mask, &si->si_mask); + return err; +} + +#if 0 +static int +setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ + CPUState *env, unsigned long mask) +{ + int err = 0; + + err |= __put_user(mask, &sc->sigc_mask); + err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp); + err |= __put_user(env->pc, &sc->sigc_pc); + err |= __put_user(env->npc, &sc->sigc_npc); + err |= __put_user(env->psr, &sc->sigc_psr); + err |= __put_user(env->gregs[1], &sc->sigc_g1); + err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0); + + return err; +} +#endif +#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) + +static void setup_frame(int sig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + struct target_signal_frame *sf; + int sigframe_size, err, i; + + /* 1. Make sure everything is clean */ + //synchronize_user_stack(); + + sigframe_size = NF_ALIGNEDSZ; + + sf = (struct target_signal_frame *) + get_sigframe(ka, env, sigframe_size); + + //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); +#if 0 + if (invalid_frame_pointer(sf, sigframe_size)) + goto sigill_and_return; +#endif + /* 2. Save the current process state */ + err = setup___siginfo(&sf->info, env, set->sig[0]); + err |= __put_user(0, &sf->extra_size); + + //err |= save_fpu_state(regs, &sf->fpu_state); + //err |= __put_user(&sf->fpu_state, &sf->fpu_save); + + err |= __put_user(set->sig[0], &sf->info.si_mask); + for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { + err |= __put_user(set->sig[i + 1], &sf->extramask[i]); + } + + for (i = 0; i < 8; i++) { + err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]); + } + for (i = 0; i < 8; i++) { + err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]); + } + if (err) + goto sigsegv; + + /* 3. signal handler back-trampoline and parameters */ + env->regwptr[UREG_FP] = h2g(sf); + env->regwptr[UREG_I0] = sig; + env->regwptr[UREG_I1] = h2g(&sf->info); + env->regwptr[UREG_I2] = h2g(&sf->info); + + /* 4. signal handler */ + env->pc = (unsigned long) ka->sa._sa_handler; + env->npc = (env->pc + 4); + /* 5. return to kernel instructions */ + if (ka->sa.sa_restorer) + env->regwptr[UREG_I7] = (unsigned long)ka->sa.sa_restorer; + else { + env->regwptr[UREG_I7] = h2g(&(sf->insns[0]) - 2); + + /* mov __NR_sigreturn, %g1 */ + err |= __put_user(0x821020d8, &sf->insns[0]); + + /* t 0x10 */ + err |= __put_user(0x91d02010, &sf->insns[1]); + if (err) + goto sigsegv; + + /* Flush instruction space. */ + //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); + // tb_flush(env); + } + return; + + //sigill_and_return: + force_sig(TARGET_SIGILL); +sigsegv: + //fprintf(stderr, "force_sig\n"); + force_sig(TARGET_SIGSEGV); +} +static inline int +restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu) +{ + int err; +#if 0 +#ifdef CONFIG_SMP + if (current->flags & PF_USEDFPU) + regs->psr &= ~PSR_EF; +#else + if (current == last_task_used_math) { + last_task_used_math = 0; + regs->psr &= ~PSR_EF; + } +#endif + current->used_math = 1; + current->flags &= ~PF_USEDFPU; +#endif +#if 0 + if (verify_area (VERIFY_READ, fpu, sizeof(*fpu))) + return -EFAULT; +#endif + +#if 0 + /* XXX: incorrect */ + err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0], + (sizeof(unsigned long) * 32)); +#endif + err |= __get_user(env->fsr, &fpu->si_fsr); +#if 0 + err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth); + if (current->thread.fpqdepth != 0) + err |= __copy_from_user(¤t->thread.fpqueue[0], + &fpu->si_fpqueue[0], + ((sizeof(unsigned long) + + (sizeof(unsigned long *)))*16)); +#endif + return err; +} + + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_rt_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env) +{ + struct target_signal_frame *sf; + uint32_t up_psr, pc, npc; + target_sigset_t set; + sigset_t host_set; + target_ulong fpu_save; + int err, i; + + sf = (struct target_signal_frame *)g2h(env->regwptr[UREG_FP]); +#if 0 + fprintf(stderr, "sigreturn\n"); + fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); +#endif + //cpu_dump_state(env, stderr, fprintf, 0); + + /* 1. Make sure we are not getting garbage from the user */ +#if 0 + if (verify_area (VERIFY_READ, sf, sizeof (*sf))) + goto segv_and_exit; +#endif + + if (((uint) sf) & 3) + goto segv_and_exit; + + err = __get_user(pc, &sf->info.si_regs.pc); + err |= __get_user(npc, &sf->info.si_regs.npc); + + if ((pc | npc) & 3) + goto segv_and_exit; + + /* 2. Restore the state */ + err |= __get_user(up_psr, &sf->info.si_regs.psr); + + /* User can only change condition codes and FPU enabling in %psr. */ + env->psr = (up_psr & (PSR_ICC /* | PSR_EF */)) + | (env->psr & ~(PSR_ICC /* | PSR_EF */)); + + env->pc = pc; + env->npc = npc; + err |= __get_user(env->y, &sf->info.si_regs.y); + for (i=0; i < 8; i++) { + err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); + } + for (i=0; i < 8; i++) { + err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); + } + + err |= __get_user(fpu_save, (target_ulong *)&sf->fpu_save); + + //if (fpu_save) + // err |= restore_fpu_state(env, fpu_save); + + /* This is pretty much atomic, no amount locking would prevent + * the races which exist anyways. + */ + err |= __get_user(set.sig[0], &sf->info.si_mask); + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + err |= (__get_user(set.sig[i], &sf->extramask[i - 1])); + } + + target_to_host_sigset_internal(&host_set, &set); + sigprocmask(SIG_SETMASK, &host_set, NULL); + + if (err) + goto segv_and_exit; + + return env->regwptr[0]; + +segv_and_exit: + force_sig(TARGET_SIGSEGV); +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); + return -ENOSYS; +} + +#elif defined(TARGET_MIPS) + +struct target_sigcontext { + uint32_t sc_regmask; /* Unused */ + uint32_t sc_status; + uint64_t sc_pc; + uint64_t sc_regs[32]; + uint64_t sc_fpregs[32]; + uint32_t sc_ownedfp; /* Unused */ + uint32_t sc_fpc_csr; + uint32_t sc_fpc_eir; /* Unused */ + uint32_t sc_used_math; + uint32_t sc_dsp; /* dsp status, was sc_ssflags */ + uint64_t sc_mdhi; + uint64_t sc_mdlo; + target_ulong sc_hi1; /* Was sc_cause */ + target_ulong sc_lo1; /* Was sc_badvaddr */ + target_ulong sc_hi2; /* Was sc_sigset[4] */ + target_ulong sc_lo2; + target_ulong sc_hi3; + target_ulong sc_lo3; +}; + +struct sigframe { + uint32_t sf_ass[4]; /* argument save space for o32 */ + uint32_t sf_code[2]; /* signal trampoline */ + struct target_sigcontext sf_sc; + target_sigset_t sf_mask; +}; + +/* Install trampoline to jump back from signal handler */ +static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) +{ + int err; + + /* + * Set up the return code ... + * + * li v0, __NR__foo_sigreturn + * syscall + */ + + err = __put_user(0x24020000 + syscall, tramp + 0); + err |= __put_user(0x0000000c , tramp + 1); + /* flush_cache_sigtramp((unsigned long) tramp); */ + return err; +} + +static inline int +setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) +{ + int err = 0; + + err |= __put_user(regs->PC, &sc->sc_pc); + + #define save_gp_reg(i) do { \ + err |= __put_user(regs->gpr[i], &sc->sc_regs[i]); \ + } while(0) + __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); + save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); + save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); + save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); + save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); + save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); + save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); + save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); + save_gp_reg(31); + #undef save_gp_reg + + err |= __put_user(regs->HI, &sc->sc_mdhi); + err |= __put_user(regs->LO, &sc->sc_mdlo); + + /* Not used yet, but might be useful if we ever have DSP suppport */ +#if 0 + if (cpu_has_dsp) { + err |= __put_user(mfhi1(), &sc->sc_hi1); + err |= __put_user(mflo1(), &sc->sc_lo1); + err |= __put_user(mfhi2(), &sc->sc_hi2); + err |= __put_user(mflo2(), &sc->sc_lo2); + err |= __put_user(mfhi3(), &sc->sc_hi3); + err |= __put_user(mflo3(), &sc->sc_lo3); + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + } + /* same with 64 bit */ + #ifdef CONFIG_64BIT + err |= __put_user(regs->hi, &sc->sc_hi[0]); + err |= __put_user(regs->lo, &sc->sc_lo[0]); + if (cpu_has_dsp) { + err |= __put_user(mfhi1(), &sc->sc_hi[1]); + err |= __put_user(mflo1(), &sc->sc_lo[1]); + err |= __put_user(mfhi2(), &sc->sc_hi[2]); + err |= __put_user(mflo2(), &sc->sc_lo[2]); + err |= __put_user(mfhi3(), &sc->sc_hi[3]); + err |= __put_user(mflo3(), &sc->sc_lo[3]); + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + } + #endif + + + #endif + + + #if 0 + err |= __put_user(!!used_math(), &sc->sc_used_math); + + if (!used_math()) + goto out; + + /* + * Save FPU state to signal context. Signal handler will "inherit" + * current FPU state. + */ + preempt_disable(); + + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context(sc); + + preempt_enable(); + out: +#endif + return err; +} + +static inline int +restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) +{ + int err = 0; + + err |= __get_user(regs->CP0_EPC, &sc->sc_pc); + + err |= __get_user(regs->HI, &sc->sc_mdhi); + err |= __get_user(regs->LO, &sc->sc_mdlo); + + #define restore_gp_reg(i) do { \ + err |= __get_user(regs->gpr[i], &sc->sc_regs[i]); \ + } while(0) + restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); + restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); + restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); + restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); + restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); + restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); + restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); + restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); + restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); + restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); + restore_gp_reg(31); + #undef restore_gp_reg + +#if 0 + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } + #ifdef CONFIG_64BIT + err |= __get_user(regs->hi, &sc->sc_hi[0]); + err |= __get_user(regs->lo, &sc->sc_lo[0]); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg); + err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg); + err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } + #endif + + err |= __get_user(used_math, &sc->sc_used_math); + conditional_used_math(used_math); + + preempt_disable(); + + if (used_math()) { + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + lose_fpu(); + } + + preempt_enable(); +#endif + return err; +} +/* + * Determine which stack to use.. + */ +static inline void * +get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) +{ + unsigned long sp; + + /* Default to using normal stack */ + sp = regs->gpr[29]; + + /* + * FPU emulator may have it's own trampoline active just + * above the user stack, 16-bytes before the next lowest + * 16 byte boundary. Try to avoid trashing it. + */ + sp -= 32; + +#if 0 + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) + sp = current->sas_ss_sp + current->sas_ss_size; +#endif + + return g2h((sp - frame_size) & ~7); +} + +static void setup_frame(int sig, struct emulated_sigaction * ka, + target_sigset_t *set, CPUState *regs) +{ + struct sigframe *frame; + int i; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto give_sigsegv; + + install_sigtramp(frame->sf_code, TARGET_NR_sigreturn); + + if(setup_sigcontext(regs, &frame->sf_sc)) + goto give_sigsegv; + + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + if(__put_user(set->sig[i], &frame->sf_mask.sig[i])) + goto give_sigsegv; + } + + /* + * Arguments to signal handler: + * + * a0 = signal number + * a1 = 0 (should be cause) + * a2 = pointer to struct sigcontext + * + * $25 and PC point to the signal handler, $29 points to the + * struct sigframe. + */ + regs->gpr[ 4] = sig; + regs->gpr[ 5] = 0; + regs->gpr[ 6] = h2g(&frame->sf_sc); + regs->gpr[29] = h2g(frame); + regs->gpr[31] = h2g(frame->sf_code); + /* The original kernel code sets CP0_EPC to the handler + * since it returns to userland using eret + * we cannot do this here, and we must set PC directly */ + regs->PC = regs->gpr[25] = ka->sa._sa_handler; + return; + +give_sigsegv: + force_sig(TARGET_SIGSEGV/*, current*/); + return; +} + +long do_sigreturn(CPUState *regs) +{ + struct sigframe *frame; + sigset_t blocked; + target_sigset_t target_set; + int i; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "do_sigreturn\n"); +#endif + frame = (struct sigframe *) regs->gpr[29]; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i])) + goto badframe; + } + + target_to_host_sigset_internal(&blocked, &target_set); + sigprocmask(SIG_SETMASK, &blocked, NULL); + + if (restore_sigcontext(regs, &frame->sf_sc)) + goto badframe; + +#if 0 + /* + * Don't let your children do this ... + */ + __asm__ __volatile__( + "move\t$29, %0\n\t" + "j\tsyscall_exit" + :/* no outputs */ + :"r" (®s)); + /* Unreached */ +#endif + + regs->PC = regs->CP0_EPC; + /* I am not sure this is right, but it seems to work + * maybe a problem with nested signals ? */ + regs->CP0_EPC = 0; + return 0; + +badframe: + force_sig(TARGET_SIGSEGV/*, current*/); + return 0; + +} + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_rt_frame: not implemented\n"); +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); + return -ENOSYS; +} + #else static void setup_frame(int sig, struct emulated_sigaction *ka, @@ -1331,6 +2014,12 @@ void process_pending_signals(void *cpu_env) k->first = q->next; if (!k->first) k->pending = 0; + + sig = gdb_handlesig (cpu_env, sig); + if (!sig) { + fprintf (stderr, "Lost signal\n"); + abort(); + } handler = k->sa._sa_handler; if (handler == TARGET_SIG_DFL) {