[XTENSA] Add support for configurable registers and coprocessors

The Xtensa architecture allows to define custom instructions and
registers. Registers that are bound to a coprocessor are only
accessible if the corresponding enable bit is set, which allows
to implement a 'lazy' context switch mechanism. Other registers
needs to be saved and restore at the time of the context switch
or during interrupt handling.

This patch adds support for these additional states:

- save and restore registers that are used by the compiler upon
  interrupt entry and exit.
- context switch additional registers unbound to any coprocessor
- 'lazy' context switch of registers bound to a coprocessor
- ptrace interface to provide access to additional registers
- update configuration files in include/asm-xtensa/variant-fsf

Signed-off-by: Chris Zankel <chris@zankel.net>
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index 42d9fd8..299be42 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -35,13 +35,17 @@
 
 extern struct task_struct *coproc_owners[];
 
-extern void release_all_cp (struct task_struct *);
-
 struct rt_sigframe
 {
 	struct siginfo info;
 	struct ucontext uc;
-	cp_state_t cpstate;
+	struct {
+		xtregs_opt_t opt;
+		xtregs_user_t user;
+#if XTENSA_HAVE_COPROCESSORS
+		xtregs_coprocessor_t cp;
+#endif
+	} xtregs;
 	unsigned char retcode[6];
 	unsigned int window[4];
 };
@@ -132,9 +136,10 @@
  */
 
 static int
-setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate,
-		 struct pt_regs *regs)
+setup_sigcontext(struct rt_sigframe __user *frame, struct pt_regs *regs)
 {
+	struct sigcontext __user *sc = &frame->uc.uc_mcontext;
+	struct thread_info *ti = current_thread_info();
 	int err = 0;
 
 #define COPY(x)	err |= __put_user(regs->x, &sc->sc_##x)
@@ -148,21 +153,32 @@
 
 	err |= flush_window_regs_user(regs);
 	err |= __copy_to_user (sc->sc_a, regs->areg, 16 * 4);
+	err |= __put_user(0, &sc->sc_xtregs);
 
-	// err |= __copy_to_user (sc->sc_a, regs->areg, XCHAL_NUM_AREGS * 4)
+	if (err)
+		return err;
 
-#if XCHAL_HAVE_CP
-# error Coprocessors unsupported
-	err |= save_cpextra(cpstate);
-	err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate);
+#if XTENSA_HAVE_COPROCESSORS
+	coprocessor_flush_all(ti);
+	coprocessor_release_all(ti);
+	err |= __copy_to_user(&frame->xtregs.cp, &ti->xtregs_cp,
+			      sizeof (frame->xtregs.cp));
 #endif
+	err |= __copy_to_user(&frame->xtregs.opt, &regs->xtregs_opt,
+			      sizeof (xtregs_opt_t));
+	err |= __copy_to_user(&frame->xtregs.user, &ti->xtregs_user,
+			      sizeof (xtregs_user_t));
+
+	err |= __put_user(err ? NULL : &frame->xtregs, &sc->sc_xtregs);
 
 	return err;
 }
 
 static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
+restore_sigcontext(struct pt_regs *regs, struct rt_sigframe __user *frame)
 {
+	struct sigcontext __user *sc = &frame->uc.uc_mcontext;
+	struct thread_info *ti = current_thread_info();
 	unsigned int err = 0;
 	unsigned long ps;
 
@@ -180,6 +196,8 @@
 	regs->windowbase = 0;
 	regs->windowstart = 1;
 
+	regs->syscall = -1;		/* disable syscall checks */
+
 	/* For PS, restore only PS.CALLINC.
 	 * Assume that all other bits are either the same as for the signal
 	 * handler, or the user mode value doesn't matter (e.g. PS.OWB).
@@ -195,8 +213,9 @@
 
 	err |= __copy_from_user(regs->areg, sc->sc_a, 16 * 4);
 
-#if XCHAL_HAVE_CP
-# error Coprocessors unsupported
+	if (err)
+		return err;
+
  	/* 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
@@ -204,20 +223,20 @@
 	 * Also, we essentially discard any coprocessor state that the
 	 * signal handler created. */
 
-	if (!err) {
-	  struct task_struct *tsk = current;
-	  release_all_cp(tsk);
-	  err |= __copy_from_user(tsk->thread.cpextra, sc->sc_cpstate, 
-	      			  XTENSA_CP_EXTRA_SIZE);
-	}
+#if XTENSA_HAVE_COPROCESSORS
+	coprocessor_release_all(ti);
+	err |= __copy_from_user(&ti->xtregs_cp, &frame->xtregs.cp,
+				sizeof (frame->xtregs.cp));
 #endif
+	err |= __copy_from_user(&ti->xtregs_user, &frame->xtregs.user,
+				sizeof (xtregs_user_t));
+	err |= __copy_from_user(&regs->xtregs_opt, &frame->xtregs.opt,
+				sizeof (xtregs_opt_t));
 
-	regs->syscall = -1;		/* disable syscall checks */
 	return err;
 }
 
 
-
 /*
  * Do a signal return; undo the signal stack.
  */
@@ -246,7 +265,7 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+	if (restore_sigcontext(regs, frame))
 		goto badframe;
 
 	ret = regs->areg[2];
@@ -359,7 +378,7 @@
 	err |= __put_user(sas_ss_flags(regs->areg[1]),
 			  &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);
+	err |= setup_sigcontext(frame, regs);
 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 	/* Create sys_rt_sigreturn syscall in stack frame */