From 09f8a6db20e6ed8eab1b2b23d09d2458f6e15062 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 12 Jan 2015 09:44:44 +0300 Subject: xtensa: add support for call0 ABI in userspace Provide a Kconfig choice to select whether only the default ABI, only call0 ABI or both are supported. The default for XEA2 is windowed, but it may change for XEA3. Call0 only runs userspace with PS.WOE disabled. Supporting both windowed and call0 ABIs is tricky, as there's no indication in the ELF binaries which ABI they use. So it is done by probing: each process is started with PS.WOE disabled, but the handler of an illegal instruction exception taken with PS.WOE retries faulting instruction after enabling PS.WOE. It must happen before any signal is delivered to the process, otherwise it may be delivered incorrectly. Signed-off-by: Max Filippov --- arch/xtensa/kernel/signal.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'arch/xtensa/kernel/signal.c') 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); -- cgit v1.2.3-59-g8ed1b