#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/elf.h>
+#include <linux/ptrace.h>
#include <asm/sigcontext.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
struct siginfo info;
/* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
char abigap[288];
-};
+} __attribute__ ((aligned (16)));
/*
current->state = TASK_INTERRUPTIBLE;
schedule();
if (do_signal(&saveset, regs))
- return regs->gpr[3];
+ return 0;
}
}
unsigned long err = 0;
unsigned long save_r13 = 0;
elf_greg_t *gregs = (elf_greg_t *)regs;
+#ifdef CONFIG_ALTIVEC
+ unsigned long msr;
+#endif
int i;
/* If this is not a signal return, we preserve the TLS in r13 */
#ifdef CONFIG_ALTIVEC
err |= __get_user(v_regs, &sc->v_regs);
+ err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
if (err)
return err;
/* Copy 33 vec registers (vr0..31 and vscr) from the stack */
- if (v_regs != 0 && (regs->msr & MSR_VEC) != 0)
- err |= __copy_from_user(current->thread.vr, v_regs, 33 * sizeof(vector128));
+ if (v_regs != 0 && (msr & MSR_VEC) != 0)
+ err |= __copy_from_user(current->thread.vr, v_regs,
+ 33 * sizeof(vector128));
else if (current->thread.used_vr)
- memset(¤t->thread.vr, 0, 33);
+ memset(current->thread.vr, 0, 33 * sizeof(vector128));
/* Always get VRSAVE back */
if (v_regs != 0)
err |= __get_user(current->thread.vrsave, (u32 __user *)&v_regs[33]);
current->thread.vrsave = 0;
#endif /* CONFIG_ALTIVEC */
+#ifndef CONFIG_SMP
+ preempt_disable();
+ if (last_task_used_math == current)
+ last_task_used_math = NULL;
+ if (last_task_used_altivec == current)
+ last_task_used_altivec = NULL;
+ preempt_enable();
+#endif
/* Force reload of FP/VEC */
regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC);
newsp = (current->sas_ss_sp + current->sas_ss_size);
}
- return (void __user *)((newsp - frame_size) & -8ul);
+ return (void __user *)((newsp - frame_size) & -16ul);
}
/*
return 0;
}
-static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
+static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
/* Handler is *really* a pointer to the function descriptor for
/* Allocate a dummy caller frame for the signal handler. */
newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
- err |= put_user(0, (unsigned long __user *)newsp);
+ err |= put_user(regs->gpr[1], (unsigned long __user *)newsp);
/* Set up "regs" so we "return" to the signal handler. */
err |= get_user(regs->nip, &funct_desc_ptr->entry);
if (err)
goto badframe;
- return;
+ if (test_thread_flag(TIF_SINGLESTEP))
+ ptrace_notify(SIGTRAP);
+
+ return 1;
badframe:
#if DEBUG_SIG
regs, frame, newsp);
#endif
force_sigsegv(signr, current);
+ return 0;
}
/*
* OK, we're invoking a handler
*/
-static void handle_signal(unsigned long sig, struct k_sigaction *ka,
- siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
+static int handle_signal(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
+ int ret;
+
/* Set up Signal Frame */
- setup_rt_frame(sig, ka, info, oldset, regs);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
- if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ if (ret && !(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(¤t->sighand->siglock);
sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
sigaddset(¤t->blocked,sig);
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
}
+
+ return ret;
}
static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
/* Whee! Actually deliver the signal. */
if (TRAP(regs) == 0x0C00)
syscall_restart(regs, &ka);
- handle_signal(signr, &ka, &info, oldset, regs);
- return 1;
+ return handle_signal(signr, &ka, &info, oldset, regs);
}
if (TRAP(regs) == 0x0C00) { /* System Call! */