#include <linux/signal.h>
#include <linux/ptrace.h>
#include <linux/personality.h>
-#include <linux/suspend.h>
#include <asm/cacheflush.h>
#include <asm/ucontext.h>
return ret;
}
+#ifdef CONFIG_IWMMXT
+
+/* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */
+#define IWMMXT_STORAGE_SIZE (0x98 + 8)
+#define IWMMXT_MAGIC0 0x12ef842a
+#define IWMMXT_MAGIC1 0x1c07ca71
+
+struct iwmmxt_sigframe {
+ unsigned long magic0;
+ unsigned long magic1;
+ unsigned long storage[0x98/4];
+};
+
+static int page_present(struct mm_struct *mm, void __user *uptr, int wr)
+{
+ unsigned long addr = (unsigned long)uptr;
+ pgd_t *pgd = pgd_offset(mm, addr);
+ if (pgd_present(*pgd)) {
+ pmd_t *pmd = pmd_offset(pgd, addr);
+ if (pmd_present(*pmd)) {
+ pte_t *pte = pte_offset_map(pmd, addr);
+ return (pte_present(*pte) && (!wr || pte_write(*pte)));
+ }
+ }
+ return 0;
+}
+
+static int copy_locked(void __user *uptr, void *kptr, size_t size, int write,
+ void (*copyfn)(void *, void __user *))
+{
+ unsigned char v, __user *userptr = uptr;
+ int err = 0;
+
+ do {
+ struct mm_struct *mm;
+
+ if (write) {
+ __put_user_error(0, userptr, err);
+ __put_user_error(0, userptr + size - 1, err);
+ } else {
+ __get_user_error(v, userptr, err);
+ __get_user_error(v, userptr + size - 1, err);
+ }
+
+ if (err)
+ break;
+
+ mm = current->mm;
+ spin_lock(&mm->page_table_lock);
+ if (page_present(mm, userptr, write) &&
+ page_present(mm, userptr + size - 1, write)) {
+ copyfn(kptr, uptr);
+ } else
+ err = 1;
+ spin_unlock(&mm->page_table_lock);
+ } while (err);
+
+ return err;
+}
+
+static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
+{
+ int err = 0;
+
+ /* the iWMMXt context must be 64 bit aligned */
+ WARN_ON((unsigned long)frame & 7);
+
+ __put_user_error(IWMMXT_MAGIC0, &frame->magic0, err);
+ __put_user_error(IWMMXT_MAGIC1, &frame->magic1, err);
+
+ /*
+ * iwmmxt_task_copy() doesn't check user permissions.
+ * Let's do a dummy write on the upper boundary to ensure
+ * access to user mem is OK all way up.
+ */
+ err |= copy_locked(&frame->storage, current_thread_info(),
+ sizeof(frame->storage), 1, iwmmxt_task_copy);
+ return err;
+}
+
+static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
+{
+ unsigned long magic0, magic1;
+ int err = 0;
+
+ /* the iWMMXt context is 64 bit aligned */
+ WARN_ON((unsigned long)frame & 7);
+
+ /*
+ * Validate iWMMXt context signature.
+ * Also, iwmmxt_task_restore() doesn't check user permissions.
+ * Let's do a dummy write on the upper boundary to ensure
+ * access to user mem is OK all way up.
+ */
+ __get_user_error(magic0, &frame->magic0, err);
+ __get_user_error(magic1, &frame->magic1, err);
+ if (!err && magic0 == IWMMXT_MAGIC0 && magic1 == IWMMXT_MAGIC1)
+ err = copy_locked(&frame->storage, current_thread_info(),
+ sizeof(frame->storage), 0, iwmmxt_task_restore);
+ return err;
+}
+
+#endif
+
/*
- * Do a signal return; undo the signal stack.
+ * Auxiliary signal frame. This saves stuff like FP state.
+ * The layout of this structure is not part of the user ABI.
*/
-struct sigframe
-{
+struct aux_sigframe {
+#ifdef CONFIG_IWMMXT
+ struct iwmmxt_sigframe iwmmxt;
+#endif
+#ifdef CONFIG_VFP
+ union vfp_state vfp;
+#endif
+};
+
+/*
+ * Do a signal return; undo the signal stack. These are aligned to 64-bit.
+ */
+struct sigframe {
struct sigcontext sc;
unsigned long extramask[_NSIG_WORDS-1];
unsigned long retcode;
+ struct aux_sigframe aux __attribute__((aligned(8)));
};
-struct rt_sigframe
-{
+struct rt_sigframe {
struct siginfo __user *pinfo;
void __user *puc;
struct siginfo info;
struct ucontext uc;
unsigned long retcode;
+ struct aux_sigframe aux __attribute__((aligned(8)));
};
static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
+ struct aux_sigframe __user *aux)
{
int err = 0;
err |= !valid_user_regs(regs);
+#ifdef CONFIG_IWMMXT
+ if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
+ err |= restore_iwmmxt_context(&aux->iwmmxt);
+#endif
+#ifdef CONFIG_VFP
+// if (err == 0)
+// err |= vfp_restore_state(&aux->vfp);
+#endif
+
return err;
}
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
- if (restore_sigcontext(regs, &frame->sc))
+ if (restore_sigcontext(regs, &frame->sc, &frame->aux))
goto badframe;
/* Send SIGTRAP if we're single-stepping */
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
- if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux))
+ goto badframe;
+
+ if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
goto badframe;
/* Send SIGTRAP if we're single-stepping */
}
static int
-setup_sigcontext(struct sigcontext __user *sc, /*struct _fpstate *fpstate,*/
+setup_sigcontext(struct sigcontext __user *sc, struct aux_sigframe __user *aux,
struct pt_regs *regs, unsigned long mask)
{
int err = 0;
__put_user_error(current->thread.address, &sc->fault_address, err);
__put_user_error(mask, &sc->oldmask, err);
+#ifdef CONFIG_IWMMXT
+ if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
+ err |= preserve_iwmmxt_context(&aux->iwmmxt);
+#endif
+#ifdef CONFIG_VFP
+// if (err == 0)
+// err |= vfp_save_state(&aux->vfp);
+#endif
+
return err;
}
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
{
unsigned long sp = regs->ARM_sp;
+ void __user *frame;
/*
* This is the X/Open sanctioned signal stack switching.
/*
* ATPCS B01 mandates 8-byte alignment
*/
- return (void __user *)((sp - framesize) & ~7);
+ frame = (void __user *)((sp - framesize) & ~7);
+
+ /*
+ * Check that we can actually write to the signal frame.
+ */
+ if (!access_ok(VERIFY_WRITE, frame, framesize))
+ frame = NULL;
+
+ return frame;
}
static int
struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame));
int err = 0;
- if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+ if (!frame)
return 1;
- err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
+ err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]);
if (_NSIG_WORDS > 1) {
err |= __copy_to_user(frame->extramask, &set->sig[1],
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame));
+ stack_t stack;
int err = 0;
- if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+ if (!frame)
return 1;
__put_user_error(&frame->info, &frame->pinfo, err);
__put_user_error(&frame->uc, &frame->puc, err);
err |= copy_siginfo_to_user(&frame->info, info);
- /* Clear all the bits of the ucontext we don't use. */
- err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+ __put_user_error(0, &frame->uc.uc_flags, err);
+ __put_user_error(NULL, &frame->uc.uc_link, err);
+
+ memset(&stack, 0, sizeof(stack));
+ stack.ss_sp = (void __user *)current->sas_ss_sp;
+ stack.ss_flags = sas_ss_flags(regs->ARM_sp);
+ stack.ss_size = current->sas_ss_size;
+ err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack));
- err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->aux,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
* arguments for the signal handler.
* -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
*/
- regs->ARM_r1 = (unsigned long)frame->pinfo;
- regs->ARM_r2 = (unsigned long)frame->puc;
+ regs->ARM_r1 = (unsigned long)&frame->info;
+ regs->ARM_r2 = (unsigned long)&frame->uc;
}
return err;
* OK, we're invoking a handler
*/
static void
-handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset,
struct pt_regs * regs, int syscall)
{
struct thread_info *thread = current_thread_info();
struct task_struct *tsk = current;
- struct k_sigaction *ka = &tsk->sighand->action[sig-1];
int usig = sig;
int ret;
spin_unlock_irq(&tsk->sighand->siglock);
}
- if (ret == 0) {
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
+ if (ret == 0)
return;
- }
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, tsk);
+ force_sigsegv(sig, tsk);
}
/*
*/
static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
{
+ struct k_sigaction ka;
siginfo_t info;
int signr;
if (!user_mode(regs))
return 0;
- if (current->flags & PF_FREEZE) {
- refrigerator(0);
+ if (try_to_freeze(0))
goto no_signal;
- }
if (current->ptrace & PT_SINGLESTEP)
ptrace_cancel_bpt(current);
- signr = get_signal_to_deliver(&info, regs, NULL);
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
- handle_signal(signr, &info, oldset, regs, syscall);
+ handle_signal(signr, &ka, &info, oldset, regs, syscall);
if (current->ptrace & PT_SINGLESTEP)
ptrace_set_bpt(current);
return 1;
regs->ARM_r7 = __NR_restart_syscall;
regs->ARM_pc -= 2;
} else {
- u32 *usp;
+ u32 __user *usp;
regs->ARM_sp -= 12;
- usp = (u32 *)regs->ARM_sp;
+ usp = (u32 __user *)regs->ARM_sp;
put_user(regs->ARM_pc, &usp[0]);
/* swi __NR_restart_syscall */