Commit 84434d1a authored by Russell King's avatar Russell King

[ARM] Rehash iwmmxt signal handling.

In the near future, VFP will want to save state onto the user stack.
Therefore, separate out the iwmmxt specific parts, and implement
a generic "safe copy to user space using random CPU instructions".
This is necessary because iwmmxt and VFP both use special CPU
instructions to load and/or save their state.
parent a0ae2651
...@@ -126,25 +126,6 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, ...@@ -126,25 +126,6 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
return ret; return ret;
} }
/*
* Do a signal return; undo the signal stack.
*/
struct sigframe
{
struct sigcontext sc;
unsigned long extramask[_NSIG_WORDS-1];
unsigned long retcode;
};
struct rt_sigframe
{
struct siginfo __user *pinfo;
void __user *puc;
struct siginfo info;
struct ucontext uc;
unsigned long retcode;
};
#ifdef CONFIG_IWMMXT #ifdef CONFIG_IWMMXT
/* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */ /* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */
...@@ -152,8 +133,15 @@ struct rt_sigframe ...@@ -152,8 +133,15 @@ struct rt_sigframe
#define IWMMXT_MAGIC0 0x12ef842a #define IWMMXT_MAGIC0 0x12ef842a
#define IWMMXT_MAGIC1 0x1c07ca71 #define IWMMXT_MAGIC1 0x1c07ca71
static int page_present(struct mm_struct *mm, unsigned long addr, int wr) 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); pgd_t *pgd = pgd_offset(mm, addr);
if (pgd_present(*pgd)) { if (pgd_present(*pgd)) {
pmd_t *pmd = pmd_offset(pgd, addr); pmd_t *pmd = pmd_offset(pgd, addr);
...@@ -165,49 +153,66 @@ static int page_present(struct mm_struct *mm, unsigned long addr, int wr) ...@@ -165,49 +153,66 @@ static int page_present(struct mm_struct *mm, unsigned long addr, int wr)
return 0; return 0;
} }
static int static int copy_locked(void __user *uptr, void *kptr, size_t size, int write,
preserve_iwmmxt_context(void *iwmmxt_save_area) 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; int err = 0;
/* the iWMMXt context must be 64 bit aligned */ /* the iWMMXt context must be 64 bit aligned */
long *iwmmxt_storage = (long *)(((long)iwmmxt_save_area + 4) & ~7); WARN_ON((unsigned long)frame & 7);
__put_user_error(IWMMXT_MAGIC0, &frame->magic0, err);
__put_user_error(IWMMXT_MAGIC1, &frame->magic1, err);
again:
__put_user_error(IWMMXT_MAGIC0, iwmmxt_storage+0, err);
__put_user_error(IWMMXT_MAGIC1, iwmmxt_storage+1, err);
/* /*
* iwmmxt_task_copy() doesn't check user permissions. * iwmmxt_task_copy() doesn't check user permissions.
* Let's do a dummy write on the upper boundary to ensure * Let's do a dummy write on the upper boundary to ensure
* access to user mem is OK all way up. * access to user mem is OK all way up.
*/ */
__put_user_error(0, iwmmxt_storage+IWMMXT_STORAGE_SIZE/4-1, err); err |= copy_locked(&frame->storage, current_thread_info(),
if (!err) { sizeof(frame->storage), 1, iwmmxt_task_copy);
/* Let's make sure the user mapping won't disappear under us */
struct mm_struct *mm = current->mm;
unsigned long addr = (unsigned long)iwmmxt_storage;
spin_lock(&mm->page_table_lock);
if ( !page_present(mm, addr, 1) ||
!page_present(mm, addr+IWMMXT_STORAGE_SIZE-1, 1) ) {
/* our user area has gone before grabbing the lock */
spin_unlock(&mm->page_table_lock);
goto again;
}
iwmmxt_task_copy(current_thread_info(), iwmmxt_storage+2);
spin_unlock(&mm->page_table_lock);
return 0;
}
return err; return err;
} }
static int static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
restore_iwmmxt_context(void *iwmmxt_save_area)
{ {
unsigned long magic0, magic1;
int err = 0; int err = 0;
long *iwmmxt_storage, magic0, magic1, dummy;
/* the iWMMXt context is 64 bit aligned */ /* the iWMMXt context is 64 bit aligned */
iwmmxt_storage = (long *)(((long)iwmmxt_save_area + 4) & ~7); WARN_ON((unsigned long)frame & 7);
/* /*
* Validate iWMMXt context signature. * Validate iWMMXt context signature.
...@@ -215,32 +220,51 @@ restore_iwmmxt_context(void *iwmmxt_save_area) ...@@ -215,32 +220,51 @@ restore_iwmmxt_context(void *iwmmxt_save_area)
* Let's do a dummy write on the upper boundary to ensure * Let's do a dummy write on the upper boundary to ensure
* access to user mem is OK all way up. * access to user mem is OK all way up.
*/ */
again: __get_user_error(magic0, &frame->magic0, err);
__get_user_error(magic0, iwmmxt_storage+0, err); __get_user_error(magic1, &frame->magic1, err);
__get_user_error(magic1, iwmmxt_storage+1, err); if (!err && magic0 == IWMMXT_MAGIC0 && magic1 == IWMMXT_MAGIC1)
if (!err && magic0 == IWMMXT_MAGIC0 && magic1 == IWMMXT_MAGIC1 && err = copy_locked(&frame->storage, current_thread_info(),
!__get_user(dummy, iwmmxt_storage+IWMMXT_STORAGE_SIZE/4-1)) { sizeof(frame->storage), 0, iwmmxt_task_restore);
/* Let's make sure the user mapping won't disappear under us */ return err;
struct mm_struct *mm = current->mm;
unsigned long addr = (unsigned long)iwmmxt_storage;
spin_lock(&mm->page_table_lock);
if ( !page_present(mm, addr, 0) ||
!page_present(mm, addr+IWMMXT_STORAGE_SIZE-1, 0) ) {
/* our user area has gone before grabbing the lock */
spin_unlock(&mm->page_table_lock);
goto again;
}
iwmmxt_task_restore(current_thread_info(), iwmmxt_storage+2);
spin_unlock(&mm->page_table_lock);
return 0;
}
return -1;
} }
#endif #endif
/*
* Auxiliary signal frame. This saves stuff like FP state.
* The layout of this structure is not part of the user ABI.
*/
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 siginfo __user *pinfo;
void __user *puc;
struct siginfo info;
struct ucontext uc;
unsigned long retcode;
struct aux_sigframe aux __attribute__((aligned(8)));
};
static int 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; int err = 0;
...@@ -264,6 +288,15 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) ...@@ -264,6 +288,15 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
err |= !valid_user_regs(regs); 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; return err;
} }
...@@ -299,13 +332,8 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) ...@@ -299,13 +332,8 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
if (restore_sigcontext(regs, &frame->sc)) if (restore_sigcontext(regs, &frame->sc, &frame->aux))
goto badframe;
#ifdef CONFIG_IWMMXT
if (test_thread_flag(TIF_USING_IWMMXT) && restore_iwmmxt_context(frame+1))
goto badframe; goto badframe;
#endif
/* Send SIGTRAP if we're single-stepping */ /* Send SIGTRAP if we're single-stepping */
if (current->ptrace & PT_SINGLESTEP) { if (current->ptrace & PT_SINGLESTEP) {
...@@ -349,17 +377,12 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) ...@@ -349,17 +377,12 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux))
goto badframe; goto badframe;
if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
goto badframe; goto badframe;
#ifdef CONFIG_IWMMXT
if (test_thread_flag(TIF_USING_IWMMXT) && restore_iwmmxt_context(frame+1))
goto badframe;
#endif
/* Send SIGTRAP if we're single-stepping */ /* Send SIGTRAP if we're single-stepping */
if (current->ptrace & PT_SINGLESTEP) { if (current->ptrace & PT_SINGLESTEP) {
ptrace_cancel_bpt(current); ptrace_cancel_bpt(current);
...@@ -374,7 +397,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) ...@@ -374,7 +397,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
} }
static int 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) struct pt_regs *regs, unsigned long mask)
{ {
int err = 0; int err = 0;
...@@ -402,6 +425,15 @@ setup_sigcontext(struct sigcontext __user *sc, /*struct _fpstate *fpstate,*/ ...@@ -402,6 +425,15 @@ setup_sigcontext(struct sigcontext __user *sc, /*struct _fpstate *fpstate,*/
__put_user_error(current->thread.address, &sc->fault_address, err); __put_user_error(current->thread.address, &sc->fault_address, err);
__put_user_error(mask, &sc->oldmask, 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; return err;
} }
...@@ -411,11 +443,6 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize) ...@@ -411,11 +443,6 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
unsigned long sp = regs->ARM_sp; unsigned long sp = regs->ARM_sp;
void __user *frame; void __user *frame;
#ifdef CONFIG_IWMMXT
if (test_thread_flag(TIF_USING_IWMMXT))
framesize = (framesize + 4 + IWMMXT_STORAGE_SIZE) & ~7;
#endif
/* /*
* This is the X/Open sanctioned signal stack switching. * This is the X/Open sanctioned signal stack switching.
*/ */
...@@ -505,18 +532,13 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg ...@@ -505,18 +532,13 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg
if (!frame) if (!frame)
return 1; 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) { if (_NSIG_WORDS > 1) {
err |= __copy_to_user(frame->extramask, &set->sig[1], err |= __copy_to_user(frame->extramask, &set->sig[1],
sizeof(frame->extramask)); sizeof(frame->extramask));
} }
#ifdef CONFIG_IWMMXT
if (test_thread_flag(TIF_USING_IWMMXT))
err |= preserve_iwmmxt_context(frame+1);
#endif
if (err == 0) if (err == 0)
err = setup_return(regs, ka, &frame->retcode, frame, usig); err = setup_return(regs, ka, &frame->retcode, frame, usig);
...@@ -547,15 +569,10 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, ...@@ -547,15 +569,10 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
stack.ss_size = current->sas_ss_size; stack.ss_size = current->sas_ss_size;
err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); 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]); regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
#ifdef CONFIG_IWMMXT
if (test_thread_flag(TIF_USING_IWMMXT))
err |= preserve_iwmmxt_context(frame+1);
#endif
if (err == 0) if (err == 0)
err = setup_return(regs, ka, &frame->retcode, frame, usig); err = setup_return(regs, ka, &frame->retcode, frame, usig);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment