summaryrefslogtreecommitdiff
path: root/arch/xtensa/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/xtensa/kernel/signal.c')
-rw-r--r--arch/xtensa/kernel/signal.c26
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);