[xtensa-cvscommit] linux/arch/xtensa/kernel signal.c,1.6,1.7
Brought to you by:
zankel
|
From: <joe...@us...> - 2003-04-23 23:20:00
|
Update of /cvsroot/xtensa/linux/arch/xtensa/kernel
In directory sc8-pr-cvs1:/tmp/cvs-serv31547/arch/xtensa/kernel
Modified Files:
signal.c
Log Message:
Save and restore coprocessor state as needed when handling signals.
Index: signal.c
===================================================================
RCS file: /cvsroot/xtensa/linux/arch/xtensa/kernel/signal.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -C2 -d -r1.6 -r1.7
*** signal.c 23 Apr 2003 00:36:27 -0000 1.6
--- signal.c 23 Apr 2003 23:19:55 -0000 1.7
***************
*** 34,37 ****
--- 34,39 ----
asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+ extern struct task_struct *coproc_owners[];
+
int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
{
***************
*** 171,178 ****
{
struct sigcontext sc;
unsigned long extramask[_NSIG_WORDS-1];
unsigned char retcode[6];
- unsigned int window[4]; /* Window of 4 registers for initial context */
unsigned int reserved[4]; /* Reserved area for chaining */
};
--- 173,181 ----
{
struct sigcontext sc;
+ struct _cpstate cpstate;
unsigned long extramask[_NSIG_WORDS-1];
unsigned char retcode[6];
unsigned int reserved[4]; /* Reserved area for chaining */
+ unsigned int window[4]; /* Window of 4 registers for initial context */
};
***************
*** 181,189 ****
struct siginfo info;
struct ucontext uc;
unsigned char retcode[6];
- unsigned int window[4]; /* Window of 4 registers for initial context */
unsigned int reserved[4]; /* Reserved area for chaining */
};
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
--- 184,219 ----
struct siginfo info;
struct ucontext uc;
+ struct _cpstate cpstate;
unsigned char retcode[6];
unsigned int reserved[4]; /* Reserved area for chaining */
+ unsigned int window[4]; /* Window of 4 registers for initial context */
};
+ static inline void
+ discard_my_cpstate(struct task_struct *tsk)
+ {
+ int i;
+ for (i = 0; i < XCHAL_CP_NUM; i++)
+ if (tsk == coproc_owners[i]) {
+ xthal_invalidate_cp(i);
+ coproc_owners[i] = 0;
+ }
+ }
+
+ static inline int
+ restore_cpextra (struct _cpstate *buf)
+ {
+ /* The signal handler may have used coprocessors in which
+ * case they are still enabled. We disable them to force a
+ * reloading of the original task's CP state by the lazy
+ * context-switching mechanisms of CP exception handling.
+ * Also, we essentially discard any coprocessor state that the
+ * signal handler created. */
+
+ struct task_struct *tsk = current;
+ discard_my_cpstate(tsk);
+ return __copy_from_user(tsk->thread.cpextra, buf, TOTAL_CPEXTRA_SIZE);
+ }
+
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
***************
*** 192,195 ****
--- 222,226 ----
unsigned int err = 0;
unsigned long ps;
+ struct _cpstate *buf;
int i;
***************
*** 249,278 ****
err |= __get_user(thread->regfile[i], &sc->sc_regfile[i]);
}
- #if (XCHAL_EXTRA_SA_SIZE > 0)
- err |= __copy_from_user(thread->cpextra,sc->sc_extra,XCHAL_EXTRA_SA_SIZE);
- #endif /* (XCHAL_EXTRA_SA_SIZE > 0) */
-
- /* XTFIXME: cp[0-7]_regs? Yes, we should copy over these array
- * contents, probably using the __copy_{to,from}_user() macros
- * in uaccess.h. For now, it doesn't affect development since
- * LinuxBE/LinuxLE do not have coprocessors. We should
- * implement this section when we're ready to test it.
- * Testing will be complex (Joe, keep your signaling test
- * cases around.)
- */
! /* thread->info is unused for now */
regs->syscall_nr = -1; /* disable syscall checks */
return err;
}
static int
! setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
! unsigned long mask)
{
struct thread_struct *thread;
! int err = 0;
! int i;
#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
--- 280,347 ----
err |= __get_user(thread->regfile[i], &sc->sc_regfile[i]);
}
! err |= __get_user(buf, &sc->sc_cpstate);
! if (buf) {
! if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
! goto badframe;
! err |= restore_cpextra(buf);
! }
regs->syscall_nr = -1; /* disable syscall checks */
return err;
+
+ badframe:
+ return 1;
}
+ static inline void
+ flush_my_cpstate(struct task_struct *tsk)
+ {
+ int i;
+ for (i = 0; i < XCHAL_CP_NUM; i++) {
+ if (tsk == coproc_owners[i]) {
+ xthal_validate_cp(i);
+ xthal_save_cpregs(tsk->thread.cpregs_ptr[i], i);
+ xthal_invalidate_cp(i);
+ /* I think this is unnecessary; we're not switching owners. */
+ /* coproc_owners[i] = 0; */
+ }
+ }
+ }
+
+ /* Return codes:
+ 0: nothing saved
+ 1: stuff to save, successful
+ -1: stuff to save, error happened
+ */
static int
! save_cpextra (struct _cpstate *buf)
! {
! #if (XCHAL_EXTRA_SA_SIZE == 0) && (XCHAL_CP_NUM == 0)
! return 0;
! #else
!
! /* XTFIXME: If a task has never used a coprocessor, there is
! no need to save and restore anything. Tracking this
! information would allow us to optimize this section.
! Perhaps we can use current->used_math or (current->flags &
! PF_USEDFPU) or define a new field in the thread
! structure. */
!
! struct task_struct *tsk = current;
! flush_my_cpstate(tsk);
! /* Note that we just copy everything: 'extra' and 'cp' state together. */
! if (__copy_to_user(buf, tsk->thread.cpextra, TOTAL_CPEXTRA_SIZE))
! return -1;
! return 1;
! #endif
! }
!
! static int
! setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate,
! struct pt_regs *regs, unsigned long mask)
{
struct thread_struct *thread;
! int i, tmp, err = 0;
#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
***************
*** 303,320 ****
err |= __put_user(thread->regfile[i], &sc->sc_regfile[i]);
}
- #if (XCHAL_EXTRA_SA_SIZE > 0)
- err |= __copy_to_user(sc->sc_extra, thread->cpextra, XCHAL_EXTRA_SA_SIZE);
- #endif /* (XCHAL_EXTRA_SA_SIZE > 0) */
-
- /* XTFIXME: cp[0-7]_regs? Yes, we should copy over these array
- * contents, probably using the __copy_{to,from}_user() macros
- * in uaccess.h. For now, it doesn't affect development since
- * LinuxBE/LinuxLE do not have coprocessors. We should
- * implement this section when we're ready to test it.
- * Testing will be complex (Joe, keep your signaling test
- * cases around.)
- */
! /* thread->info is unused for now */
/* non-iBCS2 extensions.. */
--- 372,381 ----
err |= __put_user(thread->regfile[i], &sc->sc_regfile[i]);
}
! tmp = save_cpextra(cpstate);
! if (tmp < 0)
! err = 1;
! else
! err |= __put_user(tmp ? cpstate : NULL, &sc->sc_cpstate);
/* non-iBCS2 extensions.. */
***************
*** 516,520 ****
: sig;
! err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
if (_NSIG_WORDS > 1) {
--- 577,581 ----
: sig;
! err |= setup_sigcontext(&frame->sc, &frame->cpstate, regs, set->sig[0]);
if (_NSIG_WORDS > 1) {
***************
*** 581,585 ****
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
! err |= setup_sigcontext(&frame->uc.uc_mcontext,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
--- 642,646 ----
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
! err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|