diff options
Diffstat (limited to 'arch/xtensa/kernel/signal.c')
-rw-r--r-- | arch/xtensa/kernel/signal.c | 26 |
1 files changed, 18 insertions, 8 deletions
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index fbedf2aba09d..dae83cddd6ca 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -335,7 +335,8 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, { struct rt_sigframe *frame; int err = 0, sig = ksig->sig; - unsigned long sp, ra, tp; + unsigned long sp, ra, tp, ps; + unsigned int base; sp = regs->areg[1]; @@ -385,17 +386,26 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, /* Set up registers for signal handler; preserve the threadptr */ tp = regs->threadptr; + ps = regs->ps; start_thread(regs, (unsigned long) ksig->ka.sa.sa_handler, (unsigned long) frame); - /* Set up a stack frame for a call4 - * Note: PS.CALLINC is set to one by start_thread - */ - regs->areg[4] = (((unsigned long) ra) & 0x3fffffff) | 0x40000000; - regs->areg[6] = (unsigned long) sig; - regs->areg[7] = (unsigned long) &frame->info; - regs->areg[8] = (unsigned long) &frame->uc; + /* Set up a stack frame for a call4 if userspace uses windowed ABI */ + if (ps & PS_WOE_MASK) { + base = 4; + regs->areg[base] = + (((unsigned long) ra) & 0x3fffffff) | 0x40000000; + ps = (ps & ~(PS_CALLINC_MASK | PS_OWB_MASK)) | + (1 << PS_CALLINC_SHIFT); + } else { + base = 0; + regs->areg[base] = (unsigned long) ra; + } + regs->areg[base + 2] = (unsigned long) sig; + regs->areg[base + 3] = (unsigned long) &frame->info; + regs->areg[base + 4] = (unsigned long) &frame->uc; regs->threadptr = tp; + regs->ps = ps; pr_debug("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08lx\n", current->comm, current->pid, sig, frame, regs->pc); |