|
|
|
@ -562,6 +562,12 @@ static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static inline int current_exec_domain_sig(int sig) |
|
|
|
{ |
|
|
|
return /* current->exec_domain && current->exec_domain->signal_invmap
|
|
|
|
&& sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig; |
|
|
|
} |
|
|
|
|
|
|
|
#if defined(TARGET_I386) && TARGET_ABI_BITS == 32 |
|
|
|
|
|
|
|
/* from the Linux kernel */ |
|
|
|
@ -745,11 +751,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, |
|
|
|
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
|
|
|
goto give_sigsegv; |
|
|
|
|
|
|
|
err |= __put_user((/*current->exec_domain
|
|
|
|
&& current->exec_domain->signal_invmap |
|
|
|
&& sig < 32 |
|
|
|
? current->exec_domain->signal_invmap[sig] |
|
|
|
: */ sig), |
|
|
|
err |= __put_user(current_exec_domain_sig(sig), |
|
|
|
&frame->sig); |
|
|
|
if (err) |
|
|
|
goto give_sigsegv; |
|
|
|
@ -819,11 +821,7 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, |
|
|
|
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
|
|
|
goto give_sigsegv; |
|
|
|
|
|
|
|
err |= __put_user((/*current->exec_domain
|
|
|
|
&& current->exec_domain->signal_invmap |
|
|
|
&& sig < 32 |
|
|
|
? current->exec_domain->signal_invmap[sig] |
|
|
|
: */sig), |
|
|
|
err |= __put_user(current_exec_domain_sig(sig), |
|
|
|
&frame->sig); |
|
|
|
addr = frame_addr + offsetof(struct rt_sigframe, info); |
|
|
|
err |= __put_user(addr, &frame->pinfo); |
|
|
|
@ -2406,6 +2404,309 @@ long do_rt_sigreturn(CPUState *env) |
|
|
|
return -TARGET_ENOSYS; |
|
|
|
} |
|
|
|
|
|
|
|
#elif defined(TARGET_SH4) |
|
|
|
|
|
|
|
/*
|
|
|
|
* code and data structures from linux kernel: |
|
|
|
* include/asm-sh/sigcontext.h |
|
|
|
* arch/sh/kernel/signal.c |
|
|
|
*/ |
|
|
|
|
|
|
|
struct target_sigcontext { |
|
|
|
target_ulong oldmask; |
|
|
|
|
|
|
|
/* CPU registers */ |
|
|
|
target_ulong sc_gregs[16]; |
|
|
|
target_ulong sc_pc; |
|
|
|
target_ulong sc_pr; |
|
|
|
target_ulong sc_sr; |
|
|
|
target_ulong sc_gbr; |
|
|
|
target_ulong sc_mach; |
|
|
|
target_ulong sc_macl; |
|
|
|
|
|
|
|
/* FPU registers */ |
|
|
|
target_ulong sc_fpregs[16]; |
|
|
|
target_ulong sc_xfpregs[16]; |
|
|
|
unsigned int sc_fpscr; |
|
|
|
unsigned int sc_fpul; |
|
|
|
unsigned int sc_ownedfp; |
|
|
|
}; |
|
|
|
|
|
|
|
struct target_sigframe |
|
|
|
{ |
|
|
|
struct target_sigcontext sc; |
|
|
|
target_ulong extramask[TARGET_NSIG_WORDS-1]; |
|
|
|
uint16_t retcode[3]; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct target_ucontext { |
|
|
|
target_ulong uc_flags; |
|
|
|
struct target_ucontext *uc_link; |
|
|
|
target_stack_t uc_stack; |
|
|
|
struct target_sigcontext uc_mcontext; |
|
|
|
target_sigset_t uc_sigmask; /* mask last for extensibility */ |
|
|
|
}; |
|
|
|
|
|
|
|
struct target_rt_sigframe |
|
|
|
{ |
|
|
|
struct target_siginfo info; |
|
|
|
struct target_ucontext uc; |
|
|
|
uint16_t retcode[3]; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ |
|
|
|
#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */ |
|
|
|
|
|
|
|
static abi_ulong get_sigframe(struct emulated_sigaction *ka, |
|
|
|
unsigned long sp, size_t frame_size) |
|
|
|
{ |
|
|
|
if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { |
|
|
|
sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; |
|
|
|
} |
|
|
|
|
|
|
|
return (sp - frame_size) & -8ul; |
|
|
|
} |
|
|
|
|
|
|
|
static int setup_sigcontext(struct target_sigcontext *sc, |
|
|
|
CPUState *regs, unsigned long mask) |
|
|
|
{ |
|
|
|
int err = 0; |
|
|
|
|
|
|
|
#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) |
|
|
|
COPY(gregs[0]); COPY(gregs[1]); |
|
|
|
COPY(gregs[2]); COPY(gregs[3]); |
|
|
|
COPY(gregs[4]); COPY(gregs[5]); |
|
|
|
COPY(gregs[6]); COPY(gregs[7]); |
|
|
|
COPY(gregs[8]); COPY(gregs[9]); |
|
|
|
COPY(gregs[10]); COPY(gregs[11]); |
|
|
|
COPY(gregs[12]); COPY(gregs[13]); |
|
|
|
COPY(gregs[14]); COPY(gregs[15]); |
|
|
|
COPY(gbr); COPY(mach); |
|
|
|
COPY(macl); COPY(pr); |
|
|
|
COPY(sr); COPY(pc); |
|
|
|
#undef COPY |
|
|
|
|
|
|
|
/* todo: save FPU registers here */ |
|
|
|
|
|
|
|
/* non-iBCS2 extensions.. */ |
|
|
|
err |= __put_user(mask, &sc->oldmask); |
|
|
|
|
|
|
|
return err; |
|
|
|
} |
|
|
|
|
|
|
|
static int restore_sigcontext(struct CPUState *regs, |
|
|
|
struct target_sigcontext *sc) |
|
|
|
{ |
|
|
|
unsigned int err = 0; |
|
|
|
|
|
|
|
#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) |
|
|
|
COPY(gregs[1]); |
|
|
|
COPY(gregs[2]); COPY(gregs[3]); |
|
|
|
COPY(gregs[4]); COPY(gregs[5]); |
|
|
|
COPY(gregs[6]); COPY(gregs[7]); |
|
|
|
COPY(gregs[8]); COPY(gregs[9]); |
|
|
|
COPY(gregs[10]); COPY(gregs[11]); |
|
|
|
COPY(gregs[12]); COPY(gregs[13]); |
|
|
|
COPY(gregs[14]); COPY(gregs[15]); |
|
|
|
COPY(gbr); COPY(mach); |
|
|
|
COPY(macl); COPY(pr); |
|
|
|
COPY(sr); COPY(pc); |
|
|
|
#undef COPY |
|
|
|
|
|
|
|
/* todo: restore FPU registers here */ |
|
|
|
|
|
|
|
regs->tra = -1; /* disable syscall checks */ |
|
|
|
return err; |
|
|
|
} |
|
|
|
|
|
|
|
static void setup_frame(int sig, struct emulated_sigaction *ka, |
|
|
|
target_sigset_t *set, CPUState *regs) |
|
|
|
{ |
|
|
|
struct target_sigframe *frame; |
|
|
|
abi_ulong frame_addr; |
|
|
|
int i; |
|
|
|
int err = 0; |
|
|
|
int signal; |
|
|
|
|
|
|
|
frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame)); |
|
|
|
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
|
|
|
goto give_sigsegv; |
|
|
|
|
|
|
|
signal = current_exec_domain_sig(sig); |
|
|
|
|
|
|
|
err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); |
|
|
|
|
|
|
|
for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { |
|
|
|
err |= __put_user(set->sig[i + 1], &frame->extramask[i]); |
|
|
|
} |
|
|
|
|
|
|
|
/* Set up to return from userspace. If provided, use a stub
|
|
|
|
already in userspace. */ |
|
|
|
if (ka->sa.sa_flags & TARGET_SA_RESTORER) { |
|
|
|
regs->pr = (unsigned long) ka->sa.sa_restorer; |
|
|
|
} else { |
|
|
|
/* Generate return code (system call to sigreturn) */ |
|
|
|
err |= __put_user(MOVW(2), &frame->retcode[0]); |
|
|
|
err |= __put_user(TRAP_NOARG, &frame->retcode[1]); |
|
|
|
err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]); |
|
|
|
regs->pr = (unsigned long) frame->retcode; |
|
|
|
} |
|
|
|
|
|
|
|
if (err) |
|
|
|
goto give_sigsegv; |
|
|
|
|
|
|
|
/* Set up registers for signal handler */ |
|
|
|
regs->gregs[15] = (unsigned long) frame; |
|
|
|
regs->gregs[4] = signal; /* Arg for signal handler */ |
|
|
|
regs->gregs[5] = 0; |
|
|
|
regs->gregs[6] = (unsigned long) &frame->sc; |
|
|
|
regs->pc = (unsigned long) ka->sa._sa_handler; |
|
|
|
|
|
|
|
unlock_user_struct(frame, frame_addr, 1); |
|
|
|
return; |
|
|
|
|
|
|
|
give_sigsegv: |
|
|
|
unlock_user_struct(frame, frame_addr, 1); |
|
|
|
force_sig(SIGSEGV); |
|
|
|
} |
|
|
|
|
|
|
|
static void setup_rt_frame(int sig, struct emulated_sigaction *ka, |
|
|
|
target_siginfo_t *info, |
|
|
|
target_sigset_t *set, CPUState *regs) |
|
|
|
{ |
|
|
|
struct target_rt_sigframe *frame; |
|
|
|
abi_ulong frame_addr; |
|
|
|
int i; |
|
|
|
int err = 0; |
|
|
|
int signal; |
|
|
|
|
|
|
|
frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame)); |
|
|
|
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
|
|
|
goto give_sigsegv; |
|
|
|
|
|
|
|
signal = current_exec_domain_sig(sig); |
|
|
|
|
|
|
|
err |= copy_siginfo_to_user(&frame->info, info); |
|
|
|
|
|
|
|
/* Create the ucontext. */ |
|
|
|
err |= __put_user(0, &frame->uc.uc_flags); |
|
|
|
err |= __put_user(0, (unsigned long *)&frame->uc.uc_link); |
|
|
|
err |= __put_user((void *)target_sigaltstack_used.ss_sp, |
|
|
|
&frame->uc.uc_stack.ss_sp); |
|
|
|
err |= __put_user(sas_ss_flags(regs->gregs[15]), |
|
|
|
&frame->uc.uc_stack.ss_flags); |
|
|
|
err |= __put_user(target_sigaltstack_used.ss_size, |
|
|
|
&frame->uc.uc_stack.ss_size); |
|
|
|
err |= setup_sigcontext(&frame->uc.uc_mcontext, |
|
|
|
regs, set->sig[0]); |
|
|
|
for(i = 0; i < TARGET_NSIG_WORDS; i++) { |
|
|
|
err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]); |
|
|
|
} |
|
|
|
|
|
|
|
/* Set up to return from userspace. If provided, use a stub
|
|
|
|
already in userspace. */ |
|
|
|
if (ka->sa.sa_flags & TARGET_SA_RESTORER) { |
|
|
|
regs->pr = (unsigned long) ka->sa.sa_restorer; |
|
|
|
} else { |
|
|
|
/* Generate return code (system call to sigreturn) */ |
|
|
|
err |= __put_user(MOVW(2), &frame->retcode[0]); |
|
|
|
err |= __put_user(TRAP_NOARG, &frame->retcode[1]); |
|
|
|
err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]); |
|
|
|
regs->pr = (unsigned long) frame->retcode; |
|
|
|
} |
|
|
|
|
|
|
|
if (err) |
|
|
|
goto give_sigsegv; |
|
|
|
|
|
|
|
/* Set up registers for signal handler */ |
|
|
|
regs->gregs[15] = (unsigned long) frame; |
|
|
|
regs->gregs[4] = signal; /* Arg for signal handler */ |
|
|
|
regs->gregs[5] = (unsigned long) &frame->info; |
|
|
|
regs->gregs[6] = (unsigned long) &frame->uc; |
|
|
|
regs->pc = (unsigned long) ka->sa._sa_handler; |
|
|
|
|
|
|
|
unlock_user_struct(frame, frame_addr, 1); |
|
|
|
return; |
|
|
|
|
|
|
|
give_sigsegv: |
|
|
|
unlock_user_struct(frame, frame_addr, 1); |
|
|
|
force_sig(SIGSEGV); |
|
|
|
} |
|
|
|
|
|
|
|
long do_sigreturn(CPUState *regs) |
|
|
|
{ |
|
|
|
struct target_sigframe *frame; |
|
|
|
abi_ulong frame_addr; |
|
|
|
sigset_t blocked; |
|
|
|
target_sigset_t target_set; |
|
|
|
int i; |
|
|
|
int err = 0; |
|
|
|
|
|
|
|
#if defined(DEBUG_SIGNAL) |
|
|
|
fprintf(stderr, "do_sigreturn\n"); |
|
|
|
#endif |
|
|
|
frame_addr = regs->gregs[15]; |
|
|
|
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) |
|
|
|
goto badframe; |
|
|
|
|
|
|
|
err |= __get_user(target_set.sig[0], &frame->sc.oldmask); |
|
|
|
for(i = 1; i < TARGET_NSIG_WORDS; i++) { |
|
|
|
err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1])); |
|
|
|
} |
|
|
|
|
|
|
|
if (err) |
|
|
|
goto badframe; |
|
|
|
|
|
|
|
target_to_host_sigset_internal(&blocked, &target_set); |
|
|
|
sigprocmask(SIG_SETMASK, &blocked, NULL); |
|
|
|
|
|
|
|
if (restore_sigcontext(regs, &frame->sc)) |
|
|
|
goto badframe; |
|
|
|
|
|
|
|
unlock_user_struct(frame, frame_addr, 0); |
|
|
|
return regs->gregs[0]; |
|
|
|
|
|
|
|
badframe: |
|
|
|
unlock_user_struct(frame, frame_addr, 0); |
|
|
|
force_sig(TARGET_SIGSEGV); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
long do_rt_sigreturn(CPUState *regs) |
|
|
|
{ |
|
|
|
struct target_rt_sigframe *frame; |
|
|
|
abi_ulong frame_addr; |
|
|
|
sigset_t blocked; |
|
|
|
|
|
|
|
#if defined(DEBUG_SIGNAL) |
|
|
|
fprintf(stderr, "do_rt_sigreturn\n"); |
|
|
|
#endif |
|
|
|
frame_addr = regs->gregs[15]; |
|
|
|
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) |
|
|
|
goto badframe; |
|
|
|
|
|
|
|
target_to_host_sigset(&blocked, &frame->uc.uc_sigmask); |
|
|
|
sigprocmask(SIG_SETMASK, &blocked, NULL); |
|
|
|
|
|
|
|
if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) |
|
|
|
goto badframe; |
|
|
|
|
|
|
|
if (do_sigaltstack(frame_addr + |
|
|
|
offsetof(struct target_rt_sigframe, uc.uc_stack), |
|
|
|
0, get_sp_from_cpustate(regs)) == -EFAULT) |
|
|
|
goto badframe; |
|
|
|
|
|
|
|
unlock_user_struct(frame, frame_addr, 0); |
|
|
|
return regs->gregs[0]; |
|
|
|
|
|
|
|
badframe: |
|
|
|
unlock_user_struct(frame, frame_addr, 0); |
|
|
|
force_sig(TARGET_SIGSEGV); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
static void setup_frame(int sig, struct emulated_sigaction *ka, |
|
|
|
|